list

列表是一个长度可变的连续数组,从细节上看,python中的列表是由对其他对象的引用组成的连续数组。指向这个数组的指针及其长度被保存在一个列表头结构中。这意味着,每次删除或添加一个元素时,由引用组成的数组需要重新分配。在普通链表上复杂度低的操作,对于 python的list来说复杂度会更高。

操作

复杂度

复制

O(n)

在尾部添加元素

O(1)

在指定位置插入元素

O(n)

获取元素

O(1)

修改元素

O(1)

删除元素

O(n)

遍历

O(n)

获取长度为k的切片

O(n)

获取列表长度

O(1)

在这里插入代码片

tuple元组的结构如下:

typedef struct {    
	PyObject_VAR_HEAD    
	PyObject *ob_item[1];
    /* ob_item contains space for 'ob_size' elements.     
    * Items must normally not be NULL, except during construction when     
    * the tuple is not yet visible outside the function that builds it.     
    */
    } PyTupleObject;

tuple和list相似,本质也是一个数组,但是空间大小固定。
python的tuple做了许多优化,来提升在程序中的效率。举个例子,为了提高效率,避免频繁的调用系统函数 free 和 malloc 向操作系统申请和释放空间,tuple 源文件中定义了一个 free_list:

static PyTupleObject *free_list[PyTuple_MAXSAVESIZE];

所有申请过的,小于一定大小的元组,在释放的时候会被放进这个 free_list 中以供下次使用。也就是说,如果以后需要再去创建同样的 tuple,Python 就可以直接从缓存中载入。

dict

dict将一组唯一的键映射到相应的值。在遍历字典元素时,有一点需要特别注意:字典里的keys(), values()和items()3个方法的返回值不再是列表,而是视图对象(view objects)。
视图是迭代的。视图对象可以动态查看字典的内容,因此每次字典发生变化的时候,视图都会相应的改变,见下面这个例子:

words = {'foo': 'bar', 'fizz': 'bazz'}
items= words.items()
words['spam'] = 'eggs'
print(items)   # dict_items([('foo', 'bar'), ('fizz', 'bazz'), ('spam', 'eggs')])
实现细节

CPython使用伪随机探测(pseudo-random probing)的散列表(hash table)作为字典的底层数据结构。由于这个实现细节,只有可哈希的对象才能作为字典的键。
Python中所有不可变的内置类型都是可哈希的。可变类型(如列表,字典和集合)就是不可哈希的,因此不能作为字典的键。
字典的三个基本操作(添加元素,获取元素和删除元素)的平均事件复杂度为O(1),但是他们的平摊最坏情况复杂度要高得多,为O(N)。

操作

平均复杂度

平摊最坏情况复杂度

获取元素

O(1)

O(n)

修改元素

O(1)

O(n)

删除元素

O(1)

O(n)

复制

O(n)

O(n)

遍历

O(n)

O(n)

还有一点很重要,在复制和遍历字典的操作中,最坏的复杂度中的n是字典曾经达到的最大元素数目,而不是当前的元素数目。换句话说,如果一个字典曾经元素个数很多,后来又大大减小了,那么遍历这个字典可能会花费相当长的事件。因此在某些情况下,如果需要频繁的遍历某个词典,那么最好创建一个新的字典对象,而不是仅在旧字典中删除元素。

set

set是一种鲁棒性很好的数据结构,当元素的重要性不如元素的唯一性和测试元素是否包含在集合中的效率时,这种数据结构十分有用。python的集合有两种类型:

  • set():可变的、无序的、有限的结合,其元素是唯一的、不可变的、可哈希的对象
  • frozenset():一种不可变的、可哈希的、无序的集合,其元素是唯一的、不可变的哈希对象
set([set([1, 2, 3]), set([2, 3, 4])])   # 报错TypeError: unhashable type: 'set'
set([frozenset([1, 2, 3]), frozenset([2, 3, 4])])    # 不报错

set()里的元素必须是唯一、不可变的,但是set是可变的,而frozenset是不可变的。实际上,集合被实现为带有空值的字典,只有键才是实际的集合元素。