python中几个常见的“黑盒子”之 列表list
python常见的数据类型有:字符串,布尔类型,整数,浮点数,数字,日期,列表,元祖,字典。相信前面6个大家都非常的熟悉,但是对于python的列表,元祖,字典我有时候一直在想其内部的实现是怎么样子的,它们就像一个“黑盒子”一样,下面记录一下对于“列表 list”理解过程:
其实,在最开始我一直以为python的列表是通过链表实现的,直到一天,应该说是误打误撞,当我通过交互模式创建一个列表的时候,然后通过id()函数打印出列表中每个元素的地址时,我发现它们的地址是连续的,然后推测python的列表list不是我们传统意义上面的列表(虽然这个推测应该算是误打误撞吧,真实的原因不是这个,这个每个元素地址连续也是因为正好凑巧而已,但是却引起了我的进一步探索和思考),也就是说不是通过链表实现的(因为如果是链表的话其元素地址肯定是不连续的),然后我就猜测这种内存地址连续的情况,python的列表应该是通过数组的形式进行存储实现的。
通过查看python文档:https://wiki.python.org/moin/TimeComplexity,其中记录了这么一句话:Internally, a list is represented as an array;这也进一步验证了我推测的结果。然后查看python的源码:
typedef struct {
PyObject_VAR_HEAD
PyObject **ob_item;
Py_ssize_t allocated;
} PyListObject;
其中记录了这么一个结构体(省略了源码中的大部分注释,有兴趣可以找到源码看一下),其中:
ob_item是指向列表对象的指针数组;
allocated是申请内存的槽的个数。
接着,通过源码获悉,python列表的存储形式就是以数组array的形式进行存储的,然后数组中每一个元素其实存储的是列表对象的指针。
现在我们搞明白了python列表的内部实现方式,所以进一步思考了如下问题:
1.对于列表操作,append操作肯定比insert操作效率要高:
因为,对于数组来说,用append操作从后面追加一个元素,时间复杂度来说是常量级的,但是用insert操作进行数组的插入来说,当插入第一位或者中间某一位的时候,该元素后面的所有元素都要相应的往后面挪动一位。
2.python中列表的存储形式是数组的形式,这也突出了其和链表的很大的区别:
a.当我们按照给定的索引值进行某一个元素的访问的话,数组的效率肯定是比链表的效率高出不少的。
因为,对于数组来说,我们可以直接计算出目标元素在内存中的具体位置,然后直接对其访问;但是对于链表来说,我们要做的是去遍历整个链表才可以得到目标元素。
b.但是对于插入insert操作来说,情况就和上面不同了。
因为对于链表来说,我们只要知道在哪里执行insert插入操作就可以了,无论该列表中含有多少元素,操作时间都基本是相同的,造作的成本非常低;但是对于数组就不同了,每次执行插入操作的时候,都需要移动插入点右边的所有元素。甚至有时候,因为插入的元素过多,开始分配的内存空间不够,还需要把这个列表元素整体搬到一个更大的数组中(这是我开始的猜测)。当然,对于这种情况,python的开发者早就想好了对应的方法,就是append操作通常会采用一种动态数组或向量的特定解决方案:
将内存分配得过大一些,并且等到其要溢出时,在线性时间内再次重新分配内存。
但是,这样似乎还是我上面猜测的那样,不是会让append和insert一样糟糕么,其实不是这样子的,因为就算这俩种情况都有可能去搬动大量的元素,但最主要的不同是:对于append操作,发生的可能性要小非常多,事实上,我们能够确保每次搬入的数组都大于原数组一定的比例,那么该操作的平均成本(每次搬动的开销平均分摊到每次append操作中去),这样的时间复杂度通常是常量级别的。这里也从而得出来,python的列表对内存的开销是比较大的。
python中几个常见的“黑盒子”之 列表list的更多相关文章
- python中几个常见的黑盒子之“字典dict” 与 “集合set”
这里说到"字典dict" 和 "集合set"类型,首先,先了解一下,对于python来说,标准散列机制是有hash函数提供的,对于调用一个__hash__方法: ...
- Python中执行系统命令常见的几种方法--转载
Python中执行系统命令常见的几种方法 Python中执行系统命令常见的几种方法有: (1)os.system # 仅仅在一个子终端运行系统命令,而不能获取命令执行后的返回信息 # 如果再命令行下执 ...
- python中集合set,字典dict和列表list的区别以及用法
python中set代表集合,list代表列表,dict代表字典 set和dict的区别在于,dict是存储key-value,每一个key都是唯一的,set相对于dict存储的是key,且key是唯 ...
- Python中3种内建数据结构:列表、元组和字典
Python中3种内建数据结构:列表.元组和字典 Python中有3种内建的数据结构:列表.元组和字典.参考简明Python教程 1. 列表 list是处理一组有序项目的数据结构,即你可以在一个列表中 ...
- (四)Python中的“四大才子”(字符串、列表、字典、集合)
前戏:在python中把数据序列分为可变(mutable)和不可变(immutable)两种 不可变:string.int.float.tuple 特点:相同对象只是占用一个内存地址,不管有多少个变量 ...
- python中字符串的常见操作方法
1. 字符串概念,字符串是一个容器,包含若干个字符并按照一定的顺序组织成一个整体.字符串支持索引操作. 2. 创建字符串基本语法 变量名 = "字符串信息" 变量名 = '字符串信 ...
- python中字符串的常见操作
demo:mystr = 'hello python' 1.find:mystr.find(str, start=0, end=len(mystr)),检测字符串中是否有要查询的字符,如果有返回开始的 ...
- Python中的数据类型常见方法
list() 方法 1.cmp(list1, list2):#比较两个列表的元素 2.len(list):#列表元素个数 3.max(list):#返回列表元素最大值 4.min(list):#返回列 ...
- python中几个常见的魔法方法
首先,什么是魔法方法呢?在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做"魔法"方法. __ init__()方法 当一个实例被创建的时候调用的初始 ...
随机推荐
- arcgis制作风或水流速流向图
制作风或水流速流向图 风速风向图或流速流向图相信大家都已经见过不少,但不知道有多少人会制作这样炫的专题图,下面这边文章向我们展示了当基本数据U和V矢量被存储时,怎样计算风或水流的速度和方向和对其进行符 ...
- git乱码问题解决
etc\gitconfig文件中增加以下内容: [gui] encoding = utf-8 [i18n] commitencoding = gbk [svn] pathnam ...
- [转][译]关于CSS中的float和position和z-index
原文:http://learn.shayhowe.com/advanced-html-css/detailed-css-positioning 当构建页面排版时,有不同的方法可以使用.使用哪一种方法取 ...
- DHCP snooping
DHCP snooping 技术介绍 DHCP监听(DHCP Snooping)是一种DHCP安全特性.Cisco交换机支持在每个VLAN基础上启用DHCP监听特性.通过这种特性,交换机能够拦截第 ...
- Linux常用目录及文件
1./etc/sysconfig/network 操作相关:hostname设置 2./etc/sysconfig/network-scripts/ifcfg-ethX(X为0.1等编号,一般为0) ...
- 基于angular写的一个todolist
对于新手来说,使用angularjs写一个todolist可以快速入门
- C#中Invoke 和 BeginInvoke 的区别
Control.Invoke 方法 (Delegate) :在拥有此控件的基础窗口句柄的线程上执行指定的委托. Control.BeginInvoke 方法 (Delegate) :在创建控件的基础句 ...
- 仿QQ的底部选项
效果图: item_add.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout ...
- HashTable 简述
1.解释:使用了映射函数,把值映射到对应的位置,key-> address, address是表中的存储位置,不是实际的地址: 2.Hash 函数设计, 分布合理,冲突少,利用率平衡,利用率 ...
- 在svg中的line和path根据路径返回x,y
由于path有自带的api可获得总长度,和某个长度返回的坐标. var total = d.path.getTotalLength();//返回总长度 var point = d.path.getPo ...