1Python Cookbook(第3版)

数据结构与算法

数据操作

命名切片双端队列堆操作字典运算

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第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, 6

2.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, Low

2.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:] 哪个更快?


1/12数据结构
0%