第1章:数据结构与算法
一、导读
1.1 本章学习目标
第1章讲解 Python 中常用数据结构和算法的实用技巧:命名切片、双端队列、堆操作、字典运算等。
本章核心学习目标:
- 掌握命名切片:让代码更易读
- 理解双端队列:deque 的优势
- 掌握堆操作:heapq 模块
- 理解字典运算:合并、查找、排序
1.2 为什么本章如此重要
Python 内置了丰富的数据结构,理解它们的最佳实践能写出更简洁高效的代码。
1.3 核心问题引导
命名切片如何提高代码可读性?
deque 比 list 在哪些操作上更快?
heapq 如何实现优先队列?
二、核心概念详解
2.1 命名切片
python
# 不好: 魔法数字
record = '....................100 .......513.25 ..........'
cost = int(record[20:32]) * float(record[40:48])
# 好: 命名切片
SHARES = slice(20, 32)
PRICE = slice(40, 48)
cost = int(record[SHARES]) * float(record[PRICE])
# 切片的 indices 方法
items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
s = slice(2, 8, 2)
print(s.indices(len(items))) # (2, 8, 2)
for i in range(*s.indices(len(items))):
print(items[i]) # 2, 4, 62.2 双端队列
python
from collections import deque
# deque: 两端 O(1) 的插入和删除
dq = deque([1, 2, 3])
dq.appendleft(0) # deque([0, 1, 2, 3])
dq.append(4) # deque([0, 1, 2, 3, 4])
dq.popleft() # 0
dq.pop() # 4
# 固定长度的 deque (历史最近 N 个元素)
history = deque(maxlen=5)
for i in range(10):
history.append(i)
print(list(history)) # [5, 6, 7, 8, 9]
# 旋转
dq = deque([1, 2, 3, 4, 5])
dq.rotate(2) # deque([4, 5, 1, 2, 3])
dq.rotate(-1) # deque([5, 1, 2, 3, 4])2.3 堆操作
python
import heapq
# 最小堆
nums = [5, 3, 8, 1, 9, 2]
heapq.heapify(nums) # 原地转换为堆
print(nums) # [1, 3, 2, 5, 9, 8]
heapq.heappush(nums, 0)
smallest = heapq.heappop(nums) # 0
# 最大的 N 个元素
largest_3 = heapq.nlargest(3, nums)
smallest_3 = heapq.nsmallest(3, nums)
# 优先队列
class Task:
def __init__(self, priority, name):
self.priority = priority
self.name = name
def __lt__(self, other):
return self.priority < other.priority
tasks = []
heapq.heappush(tasks, Task(3, "Low"))
heapq.heappush(tasks, Task(1, "High"))
heapq.heappush(tasks, Task(2, "Medium"))
while tasks:
task = heapq.heappop(tasks)
print(task.name) # High, Medium, Low2.4 字典运算
python
# 合并字典 (Python 3.9+)
d1 = {'a': 1, 'b': 2}
d2 = {'b': 3, 'c': 4}
merged = d1 | d2 # {'a': 1, 'b': 3, 'c': 4}
# 查找两个字典的共同键
common_keys = d1.keys() & d2.keys() # {'b'}
diff_keys = d1.keys() - d2.keys() # {'a'}
# 按值排序
prices = {'apple': 5, 'banana': 2, 'cherry': 8, 'date': 1}
sorted_by_value = dict(sorted(prices.items(), key=lambda x: x[1]))
print(sorted_by_value) # {'date': 1, 'banana': 2, 'apple': 5, 'cherry': 8}
# 字典推导
squares = {x: x*x for x in range(6)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}三、实战案例
3.1 案例一:用堆实现 Top-K 查询
python
import heapq
def top_k_largest(nums, k):
"""找最大的 k 个元素"""
return heapq.nlargest(k, nums)
def top_k_frequent(words, k):
"""找出现频率最高的 k 个单词"""
from collections import Counter
counts = Counter(words)
return heapq.nlargest(k, counts.keys(), key=counts.get)
words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
print(top_k_frequent(words, 2)) # ['apple', 'banana']四、本章小结
命名切片提高代码可读性
deque 适合两端操作和固定长度历史
heapq 实现优先队列和 Top-K 查询
字典运算支持合并、交集、排序
五、思考与练习
deque 的 maxlen 参数有什么作用?
heapq.nlargest 和 sorted()[-k:] 哪个更快?