Python中deque的基本用法与实战场景详解

江岸
江岸
发布时间:2026-10-11| 3人浏览过
原创

本文深入解析Python标准库collections模块中的deque(双端队列)。文章详细演示了deque在两端进行O(1)复杂度添加和删除元素的基础用法,介绍了通过maxlen参数限制队列长度的机制。此外,结合滑动窗口最大值、数组旋转、最大栈以及广度优先搜索(BFS)等具体算法场景,展示了deque在实际开发中的高效应用。

为什么选择 deque?

在Python中,处理队列数据时,开发者常面临列表(list)与双端队列(deque)的选择问题。虽然两者都能存储序列,但底层实现机制决定了性能差异。列表在头部进行插入或删除操作时,需要移动后续所有元素,时间复杂度为O(n);而deque基于双向链表实现,支持从两端快速添加和删除元素,时间复杂度仅为O(1)。此外,在多线程环境中,deque提供了线程安全的追加和弹出操作,无需额外加锁即可保证基本操作的原子性。

基础操作:两端高效增删

deque的核心优势在于其双向操作的便捷性。通过append()和appendleft()方法,可以分别从右侧和左侧添加元素;而pop()和popleft()则用于从对应端移除元素。这种设计使得deque在处理需要频繁在首尾进行数据交换的场景时,比列表更加高效。

from collections import deque

# 创建一个空的deque
d = deque()

# 从右侧添加元素
d.append('a')
d.append('b')
print(d)  # 输出:deque(['a', 'b'])

# 从左侧添加元素
d.appendleft('c')
print(d)  # 输出:deque(['c', 'a', 'b'])

# 从右侧移除元素
right_item = d.pop()
print(right_item)  # 输出:'b'
print(d)  # 输出:deque(['c', 'a'])

# 从左侧移除元素
left_item = d.popleft()
print(left_item)  # 输出:'c'
print(d)  # 输出:deque(['a'])

限制队列长度:maxlen参数

在某些应用场景中,我们需要维护一个固定大小的数据流,例如最近N条日志或最近K个状态。deque提供了maxlen参数来实现这一功能。当队列达到最大长度时,继续添加新元素会自动移除最早添加的元素(即队头元素)。这一特性在实现滑动窗口算法或缓存机制时非常有用。

from collections import deque

# 创建一个最大长度为3的deque
d = deque(maxlen=3)

# 添加元素
d.append('a')
d.append('b')
d.append('c')
print(d)  # 输出:deque(['a', 'b', 'c'], maxlen=3)

# 继续添加元素,最早添加的元素'a'将被移除
d.append('d')
print(d)  # 输出:deque(['b', 'c', 'd'], maxlen=3)

# 尝试从左侧添加元素,同样会移除最早添加的元素
d.appendleft('e')
print(d)  # 输出:deque(['e', 'c', 'd'], maxlen=3)

实战场景一:滑动窗口最大值

滑动窗口算法是处理数组子序列问题的常见技巧。在寻找窗口内的最大值时,如果使用暴力方法,每次移动窗口都需要重新遍历,效率较低。利用deque保存窗口内元素的索引,可以优化这一过程:维护一个递减索引队列,确保队头始终是当前窗口的最大值索引。当窗口滑动时,及时移除超出窗口范围的索引和不再具有最大值的索引,从而在O(n)时间内完成计算。

from collections import deque

def max_sliding_window(nums, k):
    # 使用deque保存窗口中的最大值索引
    window = deque()
    result = []

    for i in range(len(nums)):
        # 如果deque不为空且当前元素大于deque尾部元素对应的值,则移除尾部元素
        while window and nums[window[-1]] <= nums[i]:
            window.pop()
        # 添加当前元素的索引到deque
        window.append(i)
        # 当窗口大小达到k时,开始记录窗口内的最大值,并尝试移动窗口左边界
        if i >= k - 1:
            result.append(nums[window[0]])  # window[0]是当前窗口内最大值的索引
            # 如果deque头部的索引已经不在当前窗口内,则移除头部索引
            if window[0] <= i - k:
                window.popleft()

    return result

nums = [1, 3, -1, -3, 5, 3, 6, 7]
k = 3
print(max_sliding_window(nums, k))  # 输出:[3, 3, 5, 5, 6, 7]

实战场景二:数组旋转

数组旋转是LeetCode等算法平台上的经典题目。利用deque的rotate()方法,可以非常简洁地实现数组元素的循环移位。该方法接受一个整数参数,正数表示向右旋转,负数表示向左旋转。相比手动切片或循环赋值,使用deque不仅代码更简洁,而且避免了额外内存的分配。

from collections import deque

def rotate_array(nums, k):
    dq = deque(nums)
    dq.rotate(-k)  # 逆时针旋转 k 位,如果是顺时针旋转则直接写 k
    return list(dq)

nums = [1, 2, 3, 4, 5, 6, 7]
k = 3
rotated_nums = rotate_array(nums, k)
print(rotated_nums)  # 输出: [5, 6, 7, 1, 2, 3, 4]

实战场景三:最大栈(MaxStack)

在需要快速获取栈中最大值的场景中,常规栈操作无法在O(1)时间内完成。通过结合两个deque,一个用于存储所有元素,另一个专门维护最大值序列,可以实现常数时间内的最大值查询。当新元素入栈时,若其大于等于当前最大值栈的栈顶,则同时压入最大值栈;出栈时,若弹出的元素等于最大值栈的栈顶,则同步弹出。这种设计保证了getMax()操作的高效性。

from collections import deque

class MaxStack:
    def __init__(self):
        self.stack = deque()
        self.max_stack = deque()

    def push(self, x):
        self.stack.append(x)
        if not self.max_stack or x >= self.max_stack[-1]:
            self.max_stack.append(x)

    def pop(self):
        if self.stack:
            if self.stack[-1] == self.max_stack[-1]:
                self.max_stack.pop()
            return self.stack.pop()
        return None

    def top(self):
        return self.stack[-1] if self.stack else None

    def getMax(self):
        return self.max_stack[-1] if self.max_stack else None

# 使用示例
max_stack = MaxStack()
max_stack.push(5)
max_stack.push(7)
max_stack.push(1)
max_stack.push(5)
print(max_stack.getMax())  # 输出: 7
max_stack.pop()
print(max_stack.top())  # 输出: 5
print(max_stack.getMax())  # 输出: 7

实战场景四:广度优先搜索(BFS)

在图论算法中,广度优先搜索(BFS)需要按层级遍历节点。deque作为队列的理想选择,其popleft()操作能够确保先入队的节点先被处理,从而严格遵循广度优先的顺序。在实现BFS时,将起始节点加入deque,随后循环取出节点并遍历其邻居,将未访问的邻居加入队列,直至队列为空。

from collections import deque

def bfs(graph, root):
    visited = set()
    queue = deque([root])

    while queue:
        vertex = queue.popleft()
        print(vertex, end=" ")

        for neighbour in graph[vertex]:
            if neighbour not in visited:
                visited.add(neighbour)
                queue.append(neighbour)

# 图的邻接表表示
graph = {
    'A': ['B', 'C'],
    'B': ['D', 'E'],
    'C': ['F'],
    'D': [],
    'E': ['F'],
    'F': []
}

bfs(graph, 'A')  # 输出: A B C D E F

总结

deque凭借其双向高效操作、线程安全特性以及灵活的长度限制机制,成为Python中处理序列数据的强大工具。从基础的队列管理到复杂的滑动窗口、最大栈及图搜索算法,deque都能提供简洁且高效的解决方案。掌握deque的正确用法,有助于在编写高性能Python代码时做出更优的数据结构选择。

以上就是Python中deque基本用法与实战场景的详细内容,更多关于Python数据结构与算法优化的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。