赞
踩
双端队列:double-end-Queue(deque)
(循环队列实现双端队列,具有栈和队列的性质。)
(一)双端队列:
(1.1)双端队列图解:
双端队列(Deque:double ended queue)就是一个两端都是结尾的队列。队列的每一端都可以插入数据项和移除数据项。相对于普通队列,双端队列的入队和出队操作在两端都可进行。
(1.2)双端队列解析:
双端队列:两端都可以进队和出队的队列;
进队:前端进的元素排在后端进的元素前面;同一端,先进的元素更靠近双端队列中间。
出队:无论前端出还是后端出,先出队的元素排在前面。
总结:1)从后端进前端出或者从前端进后端出体现了先进先出的特点;
2)从后端进后端出或者从前端进前端出体现了后进先出的特点:
(1.3)双端列队使用举例:
如:有a,b,c,d元素进队,能否通过双端队列产生dacb的出队顺序?
解答:a后端进,b后端进,c后端进,d前端进,此时队中元素为dabc;d前端出,a前端出,c后端出,b前端出。
(二)双端队列的数据结构:
typedef DequeType{
ElemType array[MaxSize];
int front;
int back;
int size;/*可有可无*/
};
(三)双端队列基本操作:
(3.1)init:初始化
front=back=size=0;
(3.2)push_back:尾进
(先赋值,然后++)array[back]=elem;back=(back+1)%MaxSize;
( 注:初始化back=0.所以back第一次填数刚好填的是array[0] )
(3.3)push_front:头进
(先--,再赋值)front=(front-1+MaxSize)%MaxSize; array[front]=elem;
(注: 初始化front=0,所以front第一次填数刚好填的是array[MaxSize-1] )
(3.4)pop_back:尾出
(先--,再赋值)back=(back-1+MaxSize)%MaxSize;elem=array[back];
(3.5)pop_front:头出
(先赋值,再++) elem=array[front];front=(front+1)%MaxSize;
(3.6)get_front:取头(与pop_front类似,只不过front不变化)
elem=array[front];
(3.7)get_back:取尾 (与pop_back类似,只不过back不变化)
elem=array[(back-1+MaxSize)%MaxSize];
(3.8)length:长度
return size或者(back-front+MaxSize)%MaxSize;
(3.9)isEmpty:判空
size==0或者front==back;
(3.10)isFull:判满
size==MaxSize或者(back+1)%MaxSize==front;
(3.11)traverse:从头到尾遍历:
while(front!=back){
cout<<array[front]<<endl;
front=(front+1)%MaxSize;
}
(四) 特点
(4.1)栈的进栈出栈特点:
栈为后进先出,所以进栈与出栈相反;
如: 1)进栈为先赋值,再++;则出栈为先--,再赋值。
2)进栈为先++,再赋值;则出栈为先赋值,再--;
(4.2)队列的进队出队特点:
队列为先进先出的特点,所以进栈与出栈顺序相同:
如: 1)进队为先赋值,再++;则出队为先赋值,再++;
2)进队为先++,再赋值,则出队为先++,再赋值;
(4.3)双向队列的特点:
双向队列既有栈的特点,又有队列的特点:
1)栈的特点:push_back和pop_back;push_front和pop_front;
2)队列的特点: push_back和pop_front;push_front和pop_back;
(五)双端队列代码实现:
#include <iostream>
using namespace std;
typedef char ElemType;
#include <time.h>
#include <stdlib.h>
#define MaxSize 30
class DequeType{
public:
int front;
int back;
int size;
ElemType array[MaxSize];
public:
/*构造函数,初始化成员变量*/
DequeType (){
front=back=size=0;
}
bool isEmpty(){
if(0==size)
return true;
else return false;
}
bool isFull(){
if(MaxSize==size)
return true;
else return false;
}
bool push_back(ElemType elem){
if(isFull()) return false;
array[back]=elem;
back=(back+1)%MaxSize;
size++;
return true;
}
bool pop_front(ElemType& elem){
if(isEmpty()) return false;
elem=array[front];
front=(front+1)%MaxSize;
size--;
return true;
}
bool push_front(ElemType elem){
if(isFull()) return false;
front=(front-1+MaxSize)%MaxSize;
array[front]=elem;
size++;
return true;
}
bool pop_back(ElemType& elem){
if(isEmpty()) return false;
back=(back-1+MaxSize)%MaxSize;
elem=array[back];
size--;
return true;
}
bool get_front(ElemType & elem){
if(isEmpty()) return false;
elem=array[front];
return true;
}
bool get_back(ElemType& elem){
if(isEmpty()) return false;
elem=array[(back-1+MaxSize)%MaxSize];
return true;
}
int length(){
return size;
}
void traverse(){
if(isEmpty()){
cout<<"is empty"<<endl;
return ;
}
int temp=front;
while(temp!=back){
cout<<array[temp]<<" ";
temp=(temp+1)%MaxSize;
}
cout<<endl<<"traverse is over!"<<endl;
}
};
int main()
{ DequeType queue;
srand(time(0));
ElemType elem;
int flag;
for(int i=0;i<10;i++){
elem=rand()%26+'a';
flag=rand()%2;
if(flag){
queue.push_front(elem);
cout<<"push "<<elem<<" from front"<<endl;
}else {
queue.push_back(elem);
cout<<"push "<<elem<<" from back"<<endl;
}
}
cout<<"--------traverse start---------"<<endl;
queue.traverse();
cout << "Hello world!" << endl;
return 0;
}
(六)受限的双端队列:
受限的双端队列如:
(6.1)输入受限:
一个端点允许插入删除,另一个端点只允许删除的双端队列;
(6.2)输出受限:
一个端点允许插入删除,另一个端点只允许插入的双端队列;
(6.3)栈底相连的两个栈:
从某个端点插入的元素只能从该端点删除。
(七)双端队列的应用
在 生产者-消费者
模式中,所有消费者都从一个工作队列中取元素,一般使用阻塞队列
实现;而在 工作密取
模式中,每个消费者有其单独的工作队列,如果它完成了自己双端队列
中的全部工作,那么它就可以从其他消费者的双端队列末尾
秘密地获取工作。
工作密取 模式 对比传统的 生产者-消费者 模式,更为灵活,因为多个线程
不会因为在同一个工作队列
中抢占内容发生竞争。在大多数时候,它们只是访问自己的双端队列
。即使需要访问另一个队列时,也是从 队列的尾部获取工作,降低了队列上的竞争程度。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。