在 Python 编程中,list(列表)和 dict(字典)是两种非常重要且常用的数据结构。它们各自有独特的特点和用途,熟练掌握它们对于编写高效、简洁的 Python 代码至关重要。
一、list 介绍
list 是一种有序的可变序列,它可以容纳任意类型的元素,这些元素按照插入的顺序进行存储。我们可以通过索引来访问 list 中的元素,索引从 0 开始。例如:
my_list = [10, "hello", 3.14, True]
print(my_list[0]) # 输出10
print(my_list[2]) # 输出3.14
list 的创建非常简单,使用方括号 []
将元素括起来,元素之间用逗号分隔即可。
二、dict 介绍
dict 是一种无序的键值对集合,它使用键(key)来访问对应的值(value)。每个键值对之间用冒号:分隔,键值对之间用逗号分隔,整个字典用花括号{}括起来。例如:
my_dict = {"name": "Alice", "age": 25, "city": "New York"}
print(my_dict["name"]) # 输出Alice
print(my_dict["age"]) # 输出25
在 dict 中,键必须是唯一且不可变的,通常使用字符串、数字或元组作为键;而值可以是任意类型。
三、操作对比
操作类型 | list 操作 | dict 操作 |
---|---|---|
访问元素 | 通过索引访问,索引为整数,如my_list[index]。索引超出范围会抛出IndexError异常 | 通过键访问,如my_dict[key]。键不存在会抛出KeyError异常;也可用my_dict.get(key)方法,键不存在时返回None(可指定默认值),不抛异常 |
添加元素 | 使用append()方法在列表末尾添加一个元素,如my_list.append(new_element);使用insert()方法在指定位置插入元素,如my_list.insert(index, new_element) | 使用赋值语句添加新的键值对,如my_dict[new_key] = new_value。若键已存在,则更新对应的值 |
删除元素 | 使用pop()方法删除指定位置的元素并返回该元素,默认删除最后一个元素,如my_list.pop(index),索引超出范围抛IndexError异常;使用remove()方法删除指定值的元素,如my_list.remove(value),值不存在抛ValueError异常;使用del语句删除指定索引的元素,如del my_list[index] | 使用pop()方法删除指定键的键值对并返回对应的值,如my_dict.pop(key),键不存在抛KeyError异常(可指定默认值);使用del语句删除指定键的键值对,如del my_dict[key],键不存在抛KeyError异常;使用clear()方法清空字典中所有键值对,如my_dict.clear() |
遍历 | 使用for循环直接遍历列表元素,如for item in my_list:;使用for循环结合range()函数通过索引遍历,如for i in range(len(my_list)): print(my_list[i]) | 使用for循环遍历字典的键,如for key in my_dict:;使用for循环遍历字典的值,如for value in my_dict.values():;使用for循环遍历字典的键值对,如for key, value in my_dict.items(): |
其他常用操作 | 使用len()函数获取列表的长度,即元素的个数,如length = len(my_list);使用sort()方法对列表进行原地排序(默认升序),如my_list.sort(),也可指定reverse=True进行降序排序;使用reverse()方法反转列表元素的顺序,如my_list.reverse() | 使用len()函数获取字典中键值对的数量,如length = len(my_dict);使用keys()方法获取字典中所有键的视图,如keys_view = my_dict.keys();使用values()方法获取字典中所有值的视图,如values_view = my_dict.values();使用items()方法获取字典中所有键值对的视图,返回一个包含元组的可迭代对象,如items_view = my_dict.items() |
四、List列表数据类型常用操作性能
1、最常用的是:按索引取值和赋值(V = a[i]
, a[i] = v
)
由于列表的随机访问特性,这两个操作执行时间与列表大小无关,均为O(1)。
2、另一个是列表增长,可以选择 append()
和 _add_()
"+"
lst.append(v),执行时间是O(1)
lst = lst + [v],执行时间是O(n+k),其中k是被追加的列表长度
五、4中生成前n个整数列表的方法
- 循环链接列表(+)方法生成
def test1():
lst = []
for i in range(1000):
lst = lst + [i]
- 用append方法添加元素生成
def test2():
lst = []
for i in range(1000):
lst.append(i)
- 使用列表推导式生成
def test3():
lst = [i for i in range(1000)]
- 使用range函数生成
def test4():
lst = list(range(1000))
然后测试四种方法的运行时间
# 测试test1函数的执行时间
t1 = Timer("test1()", "from __main__ import test1")
print("test1函数执行时间: ", t1.timeit(number=1000))
# 测试test2函数的执行时间
t2 = Timer("test2()", "from __main__ import test2")
print("test2函数执行时间: ", t2.timeit(number=1000))
# 测试test3函数的执行时间
t3 = Timer("test3()", "from __main__ import test3")
print("test3函数执行时间: ", t3.timeit(number=1000))
# 测试test4函数的执行时间
t4 = Timer("test4()", "from __main__ import test4")
print("test4函数执行时间: ", t4.timeit(number=1000))
结果如下
test1函数执行时间: 0.7319497999997111
test2函数执行时间: 0.03380029999971157
test3函数执行时间: 0.01911389999804669
test4函数执行时间: 0.006437500000174623
六、Python 列表(list)常见基本操作及其大 O 数量级的表格形式呈现
操作 | 大 O 数量级 | 解释 |
---|---|---|
访问元素(通过索引) | O(1) | 可以直接通过索引访问列表中的元素,因为列表在内存中是连续存储的,通过计算偏移量就能快速定位元素。例如,对于列表 lst = [1, 2, 3, 4, 5] ,要访问 lst[2] ,计算机会直接根据元素的位置信息快速找到元素,无论列表的长度如何,访问操作的时间基本恒定。 |
元素添加(末尾添加,使用 append ) |
O(1) | 当使用 append 方法在列表末尾添加元素时,在大多数情况下,Python 的列表实现会预留一些额外的空间,当空间不足时会重新分配内存并复制元素,但从平均来看,该操作的时间复杂度是常数级。例如,执行 lst.append(6) 时,通常能快速完成添加操作,不需要移动大量元素。 |
元素插入(在头部或中间插入,使用 insert ) |
O(n) | 若使用 insert 方法在列表头部或中间插入元素,比如 lst.insert(0, 0) 或 lst.insert(2, 7) ,会导致插入位置之后的元素依次向后移动一个位置,因此需要移动元素的数量与列表长度成正比,导致时间复杂度为 O (n)。 |
元素删除(末尾删除,使用 pop 无参数) |
O(1) | 从列表末尾删除元素时,使用 pop() 方法,通常不需要移动其他元素,只需要更新列表的长度信息,所以该操作的时间复杂度是常数级。例如,对于 lst = [1, 2, 3, 4, 5] ,执行 lst.pop() 会快速删除最后一个元素。 |
元素删除(从头部或中间删除,使用 pop 带索引或 remove ) |
O(n) | 当使用 pop(i) 或 remove(value) 从列表头部或中间删除元素时,需要将删除位置之后的元素依次向前移动一个位置,操作的时间复杂度与列表长度成正比。例如,对于 lst = [1, 2, 3, 4, 5] ,执行 lst.pop(0) 或 lst.remove(3) 会导致元素的移动。 |
元素查找(通过值查找,使用 index ) |
O(n) | 当使用 index 方法查找元素时,需要遍历列表直到找到所需元素,在最坏情况下需要检查整个列表。例如,对于 lst = [1, 2, 3, 4, 5] ,执行 lst.index(3) 可能需要遍历整个列表,直到找到元素 3。 |
列表长度(使用 len ) |
O(1) | 列表内部维护了元素的数量信息,所以使用 len(lst) 可以立即获取列表的长度,时间复杂度为常数级。 |
列表排序(使用 sort ) |
O(n log n) | 内置的 sort 方法使用高效的排序算法(如 Timsort),对于大多数情况,排序操作的时间复杂度为 O (n log n)。例如,执行 lst.sort() 会对列表进行排序。 |
列表复制(使用切片) | O(n) | 当使用切片操作 new_lst = lst[:] 复制列表时,需要复制列表中的每一个元素到新列表中,因此操作的时间复杂度与列表的长度成正比。 |
列表切片(lst[i:j] ) |
O(k) | 列表切片操作 lst[i:j] 的时间复杂度取决于切片的长度 k(即 j - i ),切片越长,需要复制的元素越多,时间复杂度越高。 |
列表拼接(使用 + 或 extend ) |
O (k) 或 O (n + m) | 当使用 + 操作符拼接两个列表,如 lst1 + lst2 ,其时间复杂度为两个列表长度之和,即 O (n + m);使用 extend 方法时,时间复杂度取决于要添加的元素数量,如 lst1.extend(lst2) ,其复杂度为 O (k),其中 k 是添加元素的数量。 |
评论区