当前位置:   article > 正文

双端队列_legend

双端队列


双端队列: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)栈底相连的两个栈:
 从某个端点插入的元素只能从该端点删除。

 

(七)双端队列的应用

(7.1)工作密取

  在 生产者-消费者 模式中,所有消费者都从一个工作队列中取元素,一般使用阻塞队列实现;而在 工作密取 模式中,每个消费者有其单独的工作队列,如果它完成了自己双端队列中的全部工作,那么它就可以从其他消费者的双端队列末尾秘密地获取工作。
  工作密取 模式 对比传统的 生产者-消费者 模式,更为灵活,因为多个线程不会因为在同一个工作队列中抢占内容发生竞争。在大多数时候,它们只是访问自己的双端队列。即使需要访问另一个队列时,也是从 队列的尾部获取工作,降低了队列上的竞争程度。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/471475
推荐阅读
相关标签
  

闽ICP备14008679号