Python数据结构——list

list 列表

什么是list

列表是Python中特有的一种线性数据结构,列表是可变的,有序的,我们可以用选择操作符来改变任意位置的值,和数组不同的是,列表可以同时保存不同类型的元素(异构)。

在这里插入图片描述
在CPython中,list是一个存储指针的长度可变的数组(用C++的话来说是一个动态数组)。也就是说列表中的每个元素存储的并不是对象本身,而是一个指向对象的引用。



list有哪些功能

list的创建

我们可以直接使用选择操作符来创建列表,也可以使用list()来创建

stuff = list()
stuff = []

list的方法
索引

因为列表的本质依然是一个数组,所以也支持数组的索引操作

时间复杂度:

下表索引: O ( 1 ) O(1) O(1)

切片索引: O ( k ) O(k) O(k)


增加元素

append()

append(x)操作可以再列表的末尾添加一个元素

时间复杂度:

和数组一样,时间复杂度为 O ( 1 ) O(1) O(1)

insert()

insert(i, x)可以用来在索引i处添加元素x

时间复杂度:

要想在索引i插入某个元素,我们必须先将索引i及之后的元素向后移动一位,然后再给索引i赋值

因此插入元素时需要的后移操作的次数和列表内元素的个数有关,所以时间复杂度为 O ( n ) O(n) O(n)


extend()

extend(iterable)操作将一个可迭代对象的每一个元素添加到列表末尾

lis = [1, 2, 3, 'a', 4]
lis.extend("hello")
print(lis)
>>> 
[1, 2, 3, 'a', 4, 'h', 'e', 'l', 'l', 'o']

时间复杂度:

操作过程为先遍历读取可迭代对象的每个元素,然后添加到列表末尾,时间复杂度为 O ( k ) O(k) O(k)


删除元素

pop()

pop(i=-1)用来移除列表中的某个元素并返回,可以传入索引值,默认为-1。也就是说pop()默认移除最后一位元素。

在这里插入图片描述

这里我们可以看到,当我们使用pop()时,尽管索引为4的元素仍然指向4,但是我们的列表长度已经缩短了。有兴趣的可以参考Python的列表实现,以及resize()的用法

时间复杂度:

如果只是移除最后一位元素,那么时间复杂度为 O ( 1 ) O(1) O(1)

如果移除的是列表中的元素,那么还需要进行数据前移,前移的次数也和列表大小有关,因此时间复杂度为 O ( n ) O(n) O(n)

remove()

remove(x)操作可以移除x元素在数组中的第一个匹配项
在这里插入图片描述
当我们remove(5)时,会从列表中删除对元素5的引用。

时间复杂度:

remove(x)操作可以视为先查找再移除最后数据前移,而查找和数据前移都和数组的大小有关,所以时间复杂度为 O ( n ) O(n) O(n)。但实际使用上,remove()的操作效率较低,因为同时执行了查找和数据前移操作。

del

del操作可以根据索引值删除列表中的元素,也可以切片删除或直接删除整个列表

lis = [1,2,3,4,5]
del lis[0]
>>> 
[2, 3, 4, 5]

del lis[0:2]
>>>
[4, 5]

del lis[:]
>>> 
[]

同时,del操作也可以用来删除变量,要注意的是del删除的是引用而不是对象本身。关于del语句的详细用法以后再细说。可阅读

时间复杂度:

因为del也需要先查找并再删除后前移元素,所以时间复杂度以也是 O ( n ) O(n) O(n)


clear()

clear()操作等价于del list[:],直接删除列表全部元素

时间复杂度:

根据直觉,我认为clear()操作的时间复杂度为 O ( n ) O(n) O(n),因为我们需要不断地循环来删除所有的元素。但是在这篇文档中提到clear()的时间复杂度为 O ( 1 ) O(1) O(1)

后来在这里找到了解释clear()操作的时间复杂度取决于我们的Python解释器。对于CPthyon来说,时间复杂度确实是 O ( n ) O(n) O(n),因为list需要去主动删除每一个引用以避免内存泄漏。但是对于其他的解释器(PyPy)来说,有可能实现 O ( 1 ) O(1) O(1)

import time

for size in 10000, 100000, 1000000, 10000000:
    lis = [0] * size
    start = time.time()
    lis.clear()
    end = time.time()
    print(f'{size:<10} : {end - start}')

    
>>>
10000      : 2.47955322265625e-05
100000     : 0.0002560615539550781
1000000    : 0.00399017333984375
10000000   : 0.03731894493103027

可以看到,对于CPython来说,时间确实是呈线性增长的。


修改元素

list的元素修改直接通过索引完成

时间复杂度:

如果是下标索引,时间复杂度为 O ( 1 ) O(1) O(1)

如果是切片索引,时间复杂度为 O ( k ) O(k) O(k),可看成下标索引重复 k k k


查找元素

index()

index(x, start, end)操作可以返回元素x第一次出现的索引值,如果没找到会出现ValueError异常

时间复杂度:

为了查找特定元素,我们需要遍历列表,所以时间复杂度为 O ( n ) O(n) O(n)


count()

count(x)操作可返回元素x在列表中出现的次数

时间复杂度:

同样的,需要遍历整个列表才能得到结果,所以时间复杂度为 O ( n ) O(n) O(n)


总结

其实Python中的list和C++中的vector很类似,如果想看底层实现,可以去看看cpython解释器的具体实现

方法时间复杂度说明
[i] O ( 1 ) O(1) O(1)
[i1, i2] O ( k ) O(k) O(k)
append(x) O ( 1 ) O(1) O(1)
insert(i, x) O ( n ) O(n) O(n)
extend(iterable) O ( k ) O(k) O(k)
pop() O ( 1 ) O(1) O(1)
pop(i) O ( n ) O(n) O(n)
remove(x) O ( n ) O(n) O(n)
del O ( n ) O(n) O(n)
clear() O ( n ) O(n) O(n)取决于解释器
index(x) O ( n ) O(n) O(n)
count(x) O ( n ) O(n) O(n)

其他常用方法

Split()函数

split() 函数可以将字符串按照规律分割为小片段(也被称为字),然后存储在一个列表中,例如:

>>> string = "hello world"
>>> words = string.split()
>>> print(words)
['hello', 'world']

我们还可以指定分隔符(默认为空格),例如:

>>> string = "Hello_world_what_a_good_day"
>>> words = string.split()
>>> print(words)
['Hello_world_what_a_good_day']

>>> words = string.split("_")
>>> print(words)
['Hello', 'world', 'what', 'a', 'good', 'day']

list的优点和缺点

优点:

  1. 可以添加任意类型的元素
  2. 通过索引快速访问
  3. 适合做末尾的添加操作
  4. Python将列表设计成了一个很强大的数据结构,主要体现在列表的特性上,例如列表推导式(List comprehensions)等,详情见list的特性

缺点:

  1. 不利于做元素的删除和插入操作

list的特性

待补充…



相关章节

Python数据结构——array
Python数据结构——list
Python数据结构——tuple

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值