您的位置:

Python Deque Methods: 双端队列的增删查改操作

一、什么是双端队列

在介绍Python中的双端队列(deque)方法之前,我们先来了解一下什么是双端队列。

双端队列(Deque),全称为双端队列(Double-Ended Queue),是一种具有队列和栈的性质的数据结构。

它的两端都可以执行插入和删除操作,因此它可以在队列头部和尾部两端进行插入和删除元素的操作。

它的特点是:插入和删除元素的时间复杂度都是O(1)。


from collections import deque

# 创建双端队列
my_deque = deque()

# 在队列的左侧插入一个元素
my_deque.appendleft('a')

# 在队列的右侧插入一个元素
my_deque.append('b')

# 在队列左侧删除一个元素,并返回该元素的值
left_pop = my_deque.popleft()

# 在队列右侧删除一个元素,并返回该元素的值
right_pop = my_deque.pop()

二、双端队列的常用操作方法

1. append(item) 方法

在队列的右侧插入一个元素。


from collections import deque

# 创建双端队列
my_deque = deque()

# 在队列的右侧插入一个元素
my_deque.append('a')

2. appendleft(item) 方法

在队列的左侧插入一个元素。


from collections import deque

# 创建双端队列
my_deque = deque()

# 在队列的左侧插入一个元素
my_deque.appendleft('a')

3. clear() 方法

清空队列中的所有元素。


from collections import deque

# 创建双端队列,插入几个元素
my_deque = deque(['a', 'b', 'c'])

# 清空队列
my_deque.clear()

4. count(item) 方法

统计队列中某个元素的出现次数。


from collections import deque

# 创建双端队列,插入几个元素
my_deque = deque(['a', 'b', 'b', 'c', 'd'])

# 统计元素'b'的出现次数
b_count = my_deque.count('b')

5. extend(iterable) 方法

在队列的右侧依次插入可迭代对象中的所有元素。


from collections import deque

# 创建双端队列,插入几个元素
my_deque = deque(['a', 'b'])

# 将另一个可迭代对象的元素插入到队列的右侧
my_deque.extend(['c', 'd'])

6. extendleft(iterable) 方法

在队列的左侧依次插入可迭代对象中的所有元素。需要注意的是,元素的顺序与可迭代对象的顺序相反。


from collections import deque

# 创建双端队列,插入几个元素
my_deque = deque(['a', 'b'])

# 将另一个可迭代对象的元素插入到队列的左侧
my_deque.extendleft(['c', 'd'])  # 结果为 deque(['d', 'c', 'a', 'b'])

7. index(item, start=0, stop=len(queue)) 方法

在队列中查找某个元素的位置,并返回它第一次出现的索引。

可以指定查找的区间,start和stop参数分别表示查询区间的起始和终止位置,如果不指定,则默认搜索整个队列。


from collections import deque

# 创建双端队列,插入几个元素
my_deque = deque(['a', 'b', 'c', 'd', 'e'])

# 查找元素'd'在队列中第一次出现的索引
d_index = my_deque.index('d')

# 查找元素'd'在队列中从第3个元素(不包括第3个元素)到队列末尾的位置
d_index = my_deque.index('d', 3)

8. insert(index, item) 方法

在队列的指定位置插入一个元素。


from collections import deque

# 创建双端队列,插入几个元素
my_deque = deque(['a', 'b', 'c'])

# 在指定位置插入元素
my_deque.insert(1, 'd')  # 结果为 deque(['a', 'd', 'b', 'c'])

9. pop() 方法

从队列的右侧删除一个元素,并返回该元素的值。


from collections import deque

# 创建双端队列,插入几个元素
my_deque = deque(['a', 'b', 'c'])

# 从右侧删除一个元素并返回该元素的值
right_pop = my_deque.pop()

10. popleft() 方法

从队列的左侧删除一个元素,并返回该元素的值。


from collections import deque

# 创建双端队列,插入几个元素
my_deque = deque(['a', 'b', 'c'])

# 从左侧删除一个元素并返回该元素的值
left_pop = my_deque.popleft()

11. remove(item) 方法

从队列中删除某个元素,如果有多个,则删除第一个。


from collections import deque

# 创建双端队列,插入几个元素
my_deque = deque(['a', 'b', 'c', 'b'])

# 删除第一个元素'b'
my_deque.remove('b')

12. reverse() 方法

翻转队列中的元素。


from collections import deque

# 创建双端队列,插入几个元素
my_deque = deque(['a', 'b', 'c'])

# 反转队列中的元素
my_deque.reverse()  # 结果为 deque(['c', 'b', 'a'])

三、双端队列使用场景举例

双端队列可以在很多场景中使用,下面以Python中的实现为例:

1. 最近最少使用(LRU)缓存算法

在Python中,collections模块中的OrderedDict类就是一个经典的LRU缓存算法的实现。

OrderedDict类继承了Python内置字典类的所有方法,同时还实现了一个__setitem__方法,用于在向字典中插入新元素时维护元素的顺序。

当缓存达到最大容量时,在向OrderedDict中添加新的元素时,先删除最早被访问的元素,然后再添加新元素。


from collections import OrderedDict

# 创建最大容量为2的OrderedDict对象
cache = OrderedDict(maxlen=2)

# 向缓存中添加元素
cache[1] = 'a'
cache[2] = 'b'

# 打印当前缓存中的元素顺序
print(cache.items())  # 结果为 dict_items([(1, 'a'), (2, 'b')])

# 再添加一个元素,由于缓存大小只有2,因此会删除最早被访问的元素1
cache[3] = 'c'

# 打印当前缓存中的元素顺序
print(cache.items())  # 结果为 dict_items([(2, 'b'), (3, 'c')])

2. 广度优先搜索算法

在广度优先搜索算法中,需要使用队列来维护待访问的节点集合,而双端队列可以同时在队列的头尾进行插入和删除操作,非常适合用于实现广度优先搜索算法。

广度优先搜索算法可以应用于很多领域,包括自然语言处理、计算机视觉、图像处理等。


from collections import deque

# 定义图的邻接表表示
graph = {
    'A':{'B'},
    'B':{'C','D'},
    'C':{'D'},
    'D':{'C'},
    'E':{'D'}
}

# 广度优先搜索算法,计算从起点'A'到终点'D'的最短路径
def bfs(start, end):
    # 队列中保存路径
    queue = deque()
    queue.append([start])
    # 保存已经遍历的节点
    visited = set()

    while queue:
        # 取出路径
        path = queue.popleft()
        # 取出路径的最后一个节点
        node = path[-1]
        if node == end:
            # 如果已经到达终点,则返回路径
            return path
        if node not in visited:
            # 如果当前节点没有被访问过,则标记为已访问
            visited.add(node)
            # 在所有邻居中增加一条新路径,并把这些新路径全部加入到队列中
            for neighbor in graph[node]:
                new_path = path + [neighbor]
                queue.append(new_path)

# 测试bfs函数
print(bfs('A', 'D'))  # 结果为 ['A', 'B', 'D']

四、结语

利用双端队列可以快速高效地实现很多常见的数据结构和算法,比如实现队列、栈、LRU缓存算法和广度优先搜索算法等。

同时,Python中的collections模块中也提供了非常丰富的双端队列方法,帮助我们轻松地实现各种数据结构和算法,提高生产效率。