STlL系列之一 deque双向队列

deque双向队列是一种双向开口的连续线性空间,可以高效的在头尾两端插入和删除元素,deque在接口上和vector非常相似,下面列出deque的常用成员函数:

deque的实现比较复杂,内部会维护一个map(注意!不是STL中的map容器)即一小块连续的空间,该空间中每个元素都是指针,指向另一段(较大的)区域,这个区域称为缓冲区,缓冲区用来保存deque中的数据。因此deque在随机访问和遍历数据会比vector慢。具体的deque实现可以参考《STL源码剖析》,当然此书中使用的SGI STL与VS2008所使用的PJ STL的实现方法还是有区别的。下面给出了deque的结构图:

由于篇幅问题,deque的实现细节就不再深入了,下面给出deque的使用范例:

  1. //双向队列 deque 
  2. //by MoreWindows http://blog.youkuaiyun.com/morewindows 
  3. #include <deque> 
  4. #include <cstdio> 
  5. #include <algorithm> 
  6. using namespace std; 
  7. int main() 
  8.     deque<int> ideq(20); //Create a deque ideq with 20 elements of default value 0 
  9.     deque<int>::iterator pos; 
  10.     int i; 
  11.  
  12.     //使用assign()赋值  assign在计算机中就是赋值的意思 
  13.     for (i = 0; i < 20; ++i) 
  14.         ideq[i] = i; 
  15.      
  16.     //输出deque 
  17.     printf("输出deque中数据:\n"); 
  18.     for (i = 0; i < 20; ++i) 
  19.         printf("%d ", ideq[i]); 
  20.     putchar('\n'); 
  21.  
  22.     //在头尾加入新数据 
  23.     printf("\n在头尾加入新数据...\n"); 
  24.     ideq.push_back(100); 
  25.     ideq.push_front(i); 
  26.  
  27.     //输出deque 
  28.     printf("\n输出deque中数据:\n"); 
  29.     for (pos = ideq.begin(); pos != ideq.end(); pos++) 
  30.         printf("%d ", *pos); 
  31.     putchar('\n'); 
  32.  
  33.     //查找 
  34.     const int FINDNUMBER = 19; 
  35.     printf("\n查找%d\n", FINDNUMBER); 
  36.     pos = find(ideq.begin(), ideq.end(), FINDNUMBER); 
  37.     if (pos != ideq.end()) 
  38.         printf("find %d success\n", *pos); 
  39.     else 
  40.         printf("find failed\n"); 
  41.  
  42.     //在头尾删除数据 
  43.     printf("\n在头尾删除数据...\n"); 
  44.     ideq.pop_back(); 
  45.     ideq.pop_front(); 
  46.  
  47.     //输出deque 
  48.     printf("\n输出deque中数据:\n"); 
  49.     for (pos = ideq.begin(); pos != ideq.end(); pos++) 
  50.         printf("%d ", *pos); 
  51.     putchar('\n'); 
  52.     return 0; 

运行结果如下:

另外要注意一点。对于deque和vector来说,尽量少用erase(pos)和erase(beg,end)。因为这在中间删除数据后会导致后面的数据向前移动,从而使效率低下。

转载请标明出处,原文地址:http://blog.youkuaiyun.com/morewindows/article/details/6946811

<think>我们被要求解释双向队列deque)的使用和实现。根据引用的资料,我们可以总结以下几点:1.**双向队列的定义**:双向队列deque)全称为doubleendedqueue,即双端队列。它允许在队列的两端(头部和尾部)进行插入和删除操作。2.**双向队列的用途**:-可以用作队列(FIFO,先进先出):从一端入队,另一端出队。-可以用作栈(LIFO,后进先出):从同一端入队和出队(通常为队尾)。-由于其灵活性,可以支持多种数据结构的操作。3.**实现类比较**(根据引用[2]和[3]):-`ArrayDeque`:基于可变数组(循环数组)实现,在内存中连续存储,因此对于随机访问性能较好。适合单线程环境下频繁的两端操作。-`LinkedList`:基于双向链表实现,支持快速的插入和删除,但访问元素需要遍历,所以随机访问性能较差。同时它也实现了List接口,因此支持列表操作。-`ConcurrentLinkedDeque`:线程安全的双向队列,使用无锁算法实现,适合高并发环境。-`LinkedBlockingDeque`:线程安全且支持阻塞操作,当队列为空时,取操作会被阻塞;当队列满时,插入操作会被阻塞。4.**双向队列的基本操作**(参考引用[3]和[4]):-插入操作:`addFirst(e)`,`offerFirst(e)`,`addLast(e)`,`offerLast(e)`-删除操作:`removeFirst()`,`pollFirst()`,`removeLast()`,`pollLast()`-获取元素(不删除):`getFirst()`,`peekFirst()`,`getLast()`,`peekLast()`注意:有两套方法,一套在操作失败时抛出异常(例如`addFirst`,`removeFirst`,`getFirst`),另一套在操作失败时返回特殊值(例如`offerFirst`返回false,`pollFirst`返回null,`peekFirst`返回null)。5.**Python中的双向队列**(引用[4]):-Python的标准库`collections`提供了`deque`模块。-示例操作:`append`(右端添加)、`appendleft`(左端添加)、`pop`(右端移除)、`popleft`(左端移除)等。-示例中还有旋转操作:`rotate`,可以旋转队列中的元素。现在,我们将按照用户要求,介绍双向队列的使用和实现,注意结合引用内容,并在适当位置添加引用标识。由于用户提到了实现,我们可以简要描述两种主要实现方式:基于循环数组(如ArrayDeque)和基于双向链表(如LinkedList)。**使用示例**:我们可以提供Java和Python的简单代码示例。最后,按照要求生成相关问题。注意:回答结构要清晰,使用中文。</think> ### 双向队列Deque)的使用与实现详解 #### 一、双向队列的定义与特性 双向队列Deque, Double Ended Queue)支持在队列头部和尾部同时进行元素**插入/删除操作**,兼具队列(FIFO)和栈(LIFO)的特性。其核心特点包括: - **双端操作**:支持 `addFirst`/`addLast`(头部/尾部插入)、`removeFirst`/`removeLast`(头部/尾部删除)[^3] - **灵活应用**:可替代栈(`push` = `addFirst`, `pop` = `removeFirst`)或普通队列(`offer` = `addLast`, `poll` = `removeFirst`)[^3] - **性能优势**:在两端操作的场景下时间复杂度为 $O(1)$[^1] #### 二、双向队列的实现方式 ##### 1. 基于循环数组(如 Java 的 `ArrayDeque`) - **数据结构**:使用环形数组存储元素 - **代码示例(Java)**: ```java public class ArrayDeque<E> { private E[] elements; private int head; // 头指针 private int tail; // 尾指针 public void addFirst(E e) { head = (head - 1 + capacity) % capacity; // 头指针前移 elements[head] = e; } public void addLast(E e) { elements[tail] = e; tail = (tail + 1) % capacity; // 尾指针后移 } } ``` **适用场景**:单线程下高频两端操作(内存连续访问高效)[^2] ##### 2. 基于双向链表(如 Java 的 `LinkedList`) - **数据结构**: ```mermaid graph LR A[HEAD] ⇄ B[Node1] ⇄ C[Node2] ⇄ D[TAIL] ``` - **操作逻辑**: - `addFirst`:创建新节点指向原头节点 - `removeLast`:断开尾节点并更新指针 - **适用场景**:需要频繁插入删除或链表特性的场景[^2] ##### 3. 线程安全实现(高并发场景) - `ConcurrentLinkedDeque`:无锁并发(CAS 实现),用于多线程任务窃取[^2] - `LinkedBlockingDeque`:支持容量限制和阻塞等待 #### 三、双向队列的使用示例 ##### Python 操作(引用 `collections.deque`[^4]) ```python from collections import deque d = deque([1,2,3], maxlen=5) # 初始化最大长度 d.append(4) # 尾部添加: [1,2,3,4] d.appendleft(0) # 头部添加: [0,1,2,3,4] d.pop() # 尾部删除 → 4 d.popleft() # 头部删除 → 0 d.rotate(2) # 循环右移: [3,4,1,2] ``` ##### Java 操作(引用 `Deque` 接口[^3]) ```java Deque<Integer> deque = new ArrayDeque<>(); deque.push(10); // 头部插入 = addFirst() deque.offer(20); // 尾部插入 = addLast() int first = deque.peekFirst(); // 获取头部元素 int last = deque.pollLast(); // 删除尾部元素 ``` #### 四、关键选择建议(根据引用[^2]) | **场景需求** | **推荐实现类** | **核心优势** | |---------------------------|----------------------|------------------------------| | 高频次两端操作(单线程) | `ArrayDeque` | 内存连续,随机访问 $O(1)$ | | 需要链表特性(索引访问) | `LinkedList` | 支持任意位置插入/删除 | | 高并发非阻塞 | `ConcurrentLinkedDeque` | 无锁并发,任务窃取 | | 阻塞式有界队列 | `LinkedBlockingDeque` | 容量限制 + 阻塞等待 | #### 五、典型应用场景 1. **撤销操作栈**:使用 `push`/`pop` 实现编辑历史管理 2. **任务调度系统**:支持从队头取任务,队尾添加紧急任务 3. **滑动窗口算法**:高效维护窗口边界(如 LeetCode 239) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值