第一篇:Python 进阶-高级数据结构
1. 堆(Heap)数据结构
堆的概念与原理
堆是一种特殊的树形数据结构,它通常满足以下两个性质:
- 结构性:堆是一棵完全二叉树,即除了最后一层外,每一层的节点数都是满的,并且最后一层的节点都靠左排列。
- 堆序性:分为两种类型,最大堆和最小堆。在最大堆中,每个节点的值都大于或等于其左右子节点的值;在最小堆中,每个节点的值都小于或等于其左右子节点的值。
堆常用于实现优先队列,优先队列是一种特殊的队列,每次从队列中取出的元素是具有最高优先级的元素。在最大堆实现的优先队列中,最大元素具有最高优先级;在最小堆实现的优先队列中,最小元素具有最高优先级。堆的主要操作包括插入元素和删除堆顶元素(最大堆为最大值,最小堆为最小值)。这些操作的时间复杂度为 ( O(\log n) ),其中 ( n ) 是堆中元素的个数。这是因为堆的高度为 ( \log n ),插入和删除操作主要在堆的路径上进行调整,路径长度与堆的高度相关。
Python 中 heapq
模块的使用
Python 的 heapq
模块提供了堆数据结构的实现,默认实现的是最小堆。以下是一些常见的用法:
创建堆
可以将一个列表转换为堆结构,或者逐步向堆中添加元素。
import heapq
# 将列表转换为堆
nums = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
heapq.heapify(nums)
print(list(nums)) # 输出: [1, 1, 2, 3, 3, 9, 4, 6, 5, 5, 5]
heapq.heapify()
函数会将传入的列表原地转换为堆结构。
插入元素
使用 heapq.heappush()
函数向堆中插入元素。
import heapq
heap = []
heapq.heappush(heap, 5)
heapq.heappush(heap, 3)
heapq.heappush(heap, 7)
heapq.heappush(heap, 1)
print(list(heap)) # 输出: [1, 3, 7, 5]
获取并删除堆顶元素
使用 heapq.heappop()
函数获取并删除堆顶元素(即最小值)。
import heapq
heap = [1, 3, 7, 5]
smallest = heapq.heappop(heap)
print(smallest) # 输出: 1
print(list(heap)) # 输出: [3, 5, 7]
获取堆中最小的 ( k ) 个元素
使用 heapq.nsmallest()
函数可以获取堆中最小的 ( k ) 个元素。
import heapq
nums = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
smallest_three = heapq.nsmallest(3, nums)
print(smallest_three) # 输出: [1, 1, 2]
2. 双端队列(Deque)
双端队列的特点
双端队列(Deque,即 Double-ended Queue 的缩写)是一种特殊的队列数据结构,它允许在队列的两端进行插入和删除操作。与普通队列(只允许在一端插入,另一端删除)相比,双端队列具有更高的灵活性。其主要特点包括:
- 两端操作:可以在队列的头部和尾部执行添加和移除元素的操作,这使得双端队列在某些场景下比普通队列和栈更适用,例如实现一个支持先进先出(FIFO)和后进先出(LIFO)操作的数据结构。
- 高效性:在双端队列的两端进行插入和删除操作的时间复杂度均为 ( O(1) ),而在列表的头部插入或删除元素的时间复杂度为 ( O(n) ),因为列表需要移动元素来腾出空间或填补空缺。
collections.deque
的操作方法
Python 的 collections
模块提供了 deque
类来实现双端队列。以下是一些常用的操作方法:
创建双端队列
from collections import deque
# 创建一个空的双端队列
dq = deque()
# 创建一个带有初始元素的双端队列
dq = deque([1, 2, 3])
在两端添加元素
append(x)
:在队列尾部添加元素 ( x )。appendleft(x)
:在队列头部添加元素 ( x )。
from collections import deque
dq = deque()
dq.append(1)
dq.appendleft(2)
print(dq) # 输出: deque([2, 1])
在两端删除元素
pop()
:移除并返回队列尾部的元素。popleft()
:移除并返回队列头部的元素。
from collections import deque
dq = deque([1, 2, 3])
tail = dq.pop()
head = dq.popleft()
print(tail) # 输出: 3
print(head) # 输出: 1
print(dq) # 输出: deque([2])
访问元素
可以像列表一样通过索引访问双端队列中的元素,但由于双端队列的实现并非基于连续内存,随机访问的效率较低,时间复杂度为 ( O(n) )。
from collections import deque
dq = deque([1, 2, 3])
print(dq[1]) # 输出: 2
限制双端队列的大小
可以在创建双端队列时指定最大长度,当双端队列达到最大长度时,再添加元素会导致另一端的元素被自动移除。
from collections import deque
dq = deque(maxlen = 3)
dq.append(1)
dq.append(2)
dq.append(3)
dq.append(4)
print(dq) # 输出: deque([2, 3, 4])
通过学习堆和双端队列这两种高级数据结构及其在 Python 中的实现,你可以更高效地解决各种编程问题,尤其是涉及到优先队列和灵活数据操作的场景。如果在学习过程中有任何疑问,欢迎随时提问。同时,点赞、收藏并关注,获取更多 Python 进阶知识。