跳过正文
Python 数据结构
  1. Blog/

Python 数据结构

·1967 字·4 分钟
目录
Python - 这篇文章属于一个选集。
§ 4: 本文

Python 之所以强大和流行,其内置的、设计精良的数据结构功不可没。它们是构建任何程序的基础模块。

序列类型 —— 有序数据的世界
#

序列是 Python 中最基本的数据结构类型,它们的共同特点是其成员有序排列,可以通过索引访问。列表和元组是序列类型的两大核心。

列表 (List): 动态、可变
#

列表是 Python 中最灵活的序列类型,它是一个可变的、有序的元素集合。你可以随时添加、删除或修改其中的元素。

核心特性与常用方法:

  • 增删改查:
    • append(x): 在末尾添加。
    • extend(iterable): 合并另一个序列。
    • insert(i, x): 在指定索引 i 处插入。
    • remove(x): 按值删除第一个匹配项。
    • pop([i]): 按索引 i (默认为末尾) 移除并返回该元素。
  • 排序与反转:
    • sort(): 原地排序。
    • reverse(): 原地反转。
  • 其他:
    • copy(): 返回列表的浅拷贝。
    • count(x): 统计元素 x 出现的次数。

代码实践:

# 初始化与基本操作
fruits = ['orange', 'apple', 'pear', 'banana']
fruits.append('grape')      # 添加
fruits[1] = 'green apple'   # 修改
print(fruits) # ['orange', 'green apple', 'pear', 'banana', 'grape']

# 列表作为堆栈 (LIFO)
stack = [3, 4, 5]
stack.append(6) # 入栈
stack.pop()     # 出栈 -> 返回 6

# 列表作为队列 (FIFO) - 效率低,推荐使用 collections.deque
from collections import deque
queue = deque(["Eric", "John"])
queue.append("Terry")   # 入队
queue.popleft()         # 高效出队 -> 返回 'Eric'

关键技巧:列表推导式

列表推导式是 Python 的一大特色,它提供了一种极其优雅和简洁的方式来创建列表。

# 传统方式
squares = []
for x in range(10):
    squares.append(x**2)

# 列表推导式
squares = [x**2 for x in range(10)]
# -> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 加入条件判断
even_squares = [x**2 for x in range(10) if x % 2 == 0]
# -> [0, 4, 16, 36, 64]

元组 (Tuple): 不变
#

元组与列表类似,也是一个有序的序列,但其核心特性是不可变。一旦创建,元组的内容就无法被修改。

核心特性与应用场景:

  • 不可变性: 保证了数据的完整性,使其可以作为字典的键或集合的元素。
  • 序列解包: 这是元组最优雅的特性之一,可以用于变量赋值、函数返回等。
  • 性能: 通常情况下,元组比列表占用更少的内存,处理速度也稍快。

代码实践:

# 创建元组 (注意单元素元组需要一个逗号)
t = 123, 'hello', True
singleton = ('world',)

# 序列解包
x, y, z = t
print(f"x={x}, y={y}, z={z}") # x=123, y=hello, z=True

# 作为字典的键
location_data = {
    (39.9042, 116.4074): "Beijing",
    (31.2304, 121.4737): "Shanghai"
}

# 尝试修改元组会引发 TypeError
# t[0] = 456 # -> TypeError: 'tuple' object does not support item assignment

集合与映射 —— 无序但高效
#

与序列类型不同,这一类数据结构通常不依赖于元素的顺序,而是通过唯一的键或成员关系来组织数据。

集合 (Set): 高效、唯一
#

集合是一个无序不含重复元素的容器。它的基本用法包括成员检测、消除重复元素。集合对象支持合集、交集、差集、对称差分等数学运算。

核心特性与操作:

  • 唯一性: 自动去除重复元素。
  • 成员测试: in 操作的效率远高于列表。
  • 集合运算:
    • |union(): 并集
    • &intersection(): 交集
    • -difference(): 差集
    • ^symmetric_difference(): 对称差集

代码实践:

# 创建与去重
basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
print(basket) # {'banana', 'pear', 'apple', 'orange'} (顺序不固定)

# 成员测试
print('orange' in basket) # True

# 集合运算
a = set('abracadabra')
b = set('alacazam')
print(f"Difference (a - b): {a - b}") # {'r', 'b', 'd'}
print(f"Union (a | b): {a | b}")     # {'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}

# 与列表推导式类似,集合也支持推导式
unique_consonants = {c for c in 'programming' if c not in 'aeiou'}
print(unique_consonants) # {'p', 'r', 'g', 'm', 'n'}

📌 最佳实践: 当你需要对一个列表进行快速去重时,list(set(original_list)) 是最高效的方法。

字典 (Dictionary): 灵活映射
#

字典是 Python 的主力数据结构,它存储的是键-值 (key-value) 对。每个键必须是唯一的且不可变的。自 Python 3.7 起,字典会保持元素的插入顺序。

核心特性与操作:

  • 快速查找: 通过键来索引值,时间复杂度接近 O(1)。
  • 动态性: 可以随时添加、修改或删除键值对。
  • 常用方法:
    • get(key, default): 安全地获取值,若键不存在则返回 default 值(默认为 None)。
    • keys(): 返回所有键的视图。
    • values(): 返回所有值的视图。
    • items(): 返回所有 (键, 值) 对的视图,常用于循环。

代码实践:

# 创建字典
tel = {'jack': 4098, 'sape': 4139}
tel['guido'] = 4127 # 添加新条目
print(tel) # {'jack': 4098, 'sape': 4139, 'guido': 4127}

# 安全访问
print(tel.get('sape'))       # 4139
print(tel.get('non_exist'))  # None

# 字典推导式
power_of_two = {x: 2**x for x in range(5)}
print(power_of_two) # {0: 1, 1: 2, 2: 4, 3: 8, 4: 16}

操作数据结构的通用技巧
#

掌握了数据结构本身后,我们还需要一些通用的“招式”来高效地操作它们。

del 语句:通用的删除利器
#

del 是一个通用的 Python 语句 (Statement),而非特定数据结构的方法 (Method)。它的适用范围非常广泛,是 Python 语言核心语法的一部分,其核心作用是“解除绑定”——即移除一个名称与一个对象之间的关联。

  • 删除列表元素或切片: del my_list[0], del my_list[2:5]
  • 删除字典键值对: del my_dict['key']
  • 删除整个变量: del my_variable (从命名空间中移除)

辨析 del, .pop(), 和 .remove()

操作方式del list[i]list.pop(i)list.remove(value)
作用目标索引或切片索引 (默认为-1)第一个匹配的
返回值None (无)被删除的元素None (无)
核心场景静默地删除,不关心其值。需要使用被删除的元素。只知道值,不知道位置。

更 Pythonic 的遍历
#

Python 提供了多种优雅的循环技巧,让代码更具可读性。

  • 遍历字典: 使用 .items() 同时获取键和值。

    knights = {'gallahad': 'the pure', 'robin': 'the brave'}
    for k, v in knights.items():
        print(k, v)
    
  • 遍历序列时获取索引: 使用 enumerate()

    for i, v in enumerate(['tic', 'tac', 'toe']):
        print(i, v) # 0 tic, 1 tac, 2 toe
    
  • 同时遍历多个序列: 使用 zip() 将它们“拉”在一起。

    questions = ['name', 'quest', 'color']
    answers = ['lancelot', 'the holy grail', 'blue']
    for q, a in zip(questions, answers):
        print(f'What is your {q}? It is {a}.')
    

总结:选择正确的工具
#

选择哪种数据结构,取决于具体需求。下面是一个快速参考:

数据结构可变性 (Mutable)有序性 (Ordered)唯一性 (Unique)核心用途
列表 (List)✅ 是✅ 是❌否通用、灵活的元素序列
元组 (Tuple)❌否✅ 是❌否不可变的数据记录,用作键
集合 (Set)✅ 是❌否✅ 是去重、成员测试、数学运算
字典 (Dict)✅ 是✅ 是 (自 3.7)键唯一存储键值对,快速查找
Python - 这篇文章属于一个选集。
§ 4: 本文