五、队列(Queue)

一、概述

队列(queue): 只允许在一端进行插入 (队尾) 操作,而在另一端 (队头) 进行删除操作的线性表。
队头:删除操作的一端——front
队尾:插入操作的一端——rear

特点:先进先出(First In First Out)
在这里插入图片描述
其他常用队列:循环队列、阻塞队列、并发队列。

二、队列的抽象数据类型

ADT 队列 (Queue)
Data
	同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系
Opreation
	InitQueue(*Q):                初始化操作,建立一个空队列Q。
	DestroyQueue(*Q):             若队列Q存在,则销毁它。
	ClearQueue(*Q):               将队列Q清空。
	QueueEmpty(Q):                若队列为空,返回true,否则返回false。
	GetHead(Q,*e):                若队列Q存在且非空

二、C++队列的方法

  1. back()——返回最后一个元素;
  2. empty()——如果队列空则返回true,否则返回false;
  3. front()——返回第一个元素;
  4. pop()——从队头删除第一个元素;
  5. push()——在队尾插入一个元素;
  6. size()——返回队列中元素的大小;
#include<iostream>
#include<queue>
using namespace std;

int main()
{
    queue<int> que;
    // 入队
    for(int i = 0; i < 50; i++)
    {
        que.push(i);
    }
    cout<<"the size of queue:"<<que.size()<<endl;
    while(!que.empty())
    {
        cout<<"the front element of queue:"<<que.front()<<"    ";
        cout<<"the rear element of queue:"<<que.back()<<endl;
        que.pop();
    }
    cout<<"the size of queue:"<<que.size()<<endl;
    return 0;
}

三、实现

1、顺序队列——数组实现

  • 顺序队列需事先确定队列的大小,不支持动态分配存储空间,所以插入和删除元素比较省时,但是会造成空间的浪费。

解决方法:循环队列 =》解决空间浪费的问题
循环队列的实现:

#include <iostream>
using namespace std;

const int MAXSIZE = 1000;
typedef int ELEMTYPE;
const int N = 10;
typedef struct{
    ELEMTYPE data[MAXSIZE];
    int head;   /*队头指针*/
    int rear;   /*队尾指针*/
}Queue;

Queue Q;
void initQueue(Queue &Q);
void printQueue(Queue &Q);
bool isQueueEmpty(Queue &Q);
bool isQueueFull(Queue &Q);
bool EnQueue(Queue &Q, ELEMTYPE e);
bool DeQueue(Queue &Q, ELEMTYPE &e);

int main()
{
    for(int i = 0; i < N; i++)
    {
        EnQueue(Q, i);
    }
    printQueue(Q);
    return 0;
}


void initQueue(Queue &Q)
{
    Q.head = 0;
    Q.rear = 0;
}
void printQueue(Queue &Q)
{
    ELEMTYPE e;
    while(!isQueueEmpty(Q))
    {
        DeQueue(Q,e);
        cout<<e<<" ";
    }
    cout<<endl;
}
bool isQueueEmpty(Queue &Q)
{
    if(Q.head == Q.rear)
        return true;
    else
        return false;
}
bool isQueueFull(Queue &Q)
{
    if((Q.rear+1)%MAXSIZE == Q.head)
        return true;
    else
        return false;
}
bool EnQueue(Queue &Q, ELEMTYPE e)
{
    if(isQueueFull(Q))
        return false;
    Q.rear = (Q.rear+1)%MAXSIZE;
    Q.data[Q.rear] = e;
    return true;
}
bool DeQueue(Queue &Q, ELEMTYPE &e)
{
    if(isQueueEmpty(Q))
        return false;
    Q.head = (Q.head+1)%MAXSIZE;
    e = Q.data[Q.head];
    return true;
}

2、链式队列——链表实现

  • 可以不需要事先知道队列的大小,支持动态和释放空间,但是插入和删除操作比较耗时
#include <iostream>
using namespace std; 
struct NODE//双向链表基本单元结构
{
    int data;
    NODE *next;//后继指针
    NODE *pre;//前驱指针
}; 
class QUEUE//定义queue类封装数据和实现
{
private:
    NODE *front;//队头指针
    NODE *tail;//队尾指针
    unsigned size; 
public:
    QUEUE();
    ~QUEUE(){};
    void initialize();  //初始化
    void enqueue(int n); //入队
    void dequeue();  //出队
    int get_front();  //获取元素
    void clear();  //清空队列
    int get_size();  //返回元素个数
    bool isempty();  //判断是否为空
    void display_queue(); //输出队列
}; 
QUEUE::QUEUE()
{
    initialize();
} 
void QUEUE::initialize()
{
    //初始化头部和尾部指针
    front = new NODE();
    tail = new NODE();
    //将头尾连接
    front->data = tail->data = 0;
    front->pre = tail->next = NULL;
    front->next = tail;
    tail->pre = front;
    size = 0;  //设置元素个数为0
} 
void QUEUE::enqueue(int n)
{
    //开辟新节点
    NODE *new_ele = new NODE();
    //设置数据
    new_ele->data = n; 
   //将新节点插入到双向链表尾部
    tail->pre->next = new_ele; 
   new_ele->next = tail;
    new_ele->pre = tail->pre;
    tail->pre = new_ele;
     size++;  //元素个数加1
} 
void QUEUE::dequeue()
{
    if (isempty())//避开对空队列的操作
    {
        cout << "queue is empty" << endl; 
        return;
    }
    //获取删除将要删除的元素指针
    NODE *temp = front->next;
    front->next = temp->next;
    temp->next->pre = front; 
   delete(temp);//释放内存
    size--;
}    
int QUEUE::get_front()
{
    if (front->next != tail)
        return front->next->data;
    else
        cout << "empty queque" << endl;
    return -1;
} 
void QUEUE::clear()
{
    NODE *temp = front;
    //遍历链表释放所有节点内存 
    while(temp != tail)
    {
        NODE *del_data = temp;
        temp = temp->next;
        delete(del_data);
        }
    //调用函数重新初始化
    initialize();
}
int QUEUE::get_size()
{
    return size;
} 
void QUEUE::display_queue()
{
    NODE *temp = front->next;
    while (temp != tail)
    {
        cout << temp->data << " ";
        temp = temp->next;
    }
    if (isempty())
        cout << "queue is empty" << endl;
    else
        cout << endl;
}
bool QUEUE::isempty()
{
    return front->next == tail;
}
int main(int argc, char const *argv[])
{
    QUEUE que; 
   /*     *do somthing here     */    
    return 0;
}

3、循环队列

  • 关键:判断队列是空对还是满队
    • 空:head == tail
    • 满:(tail+1)%n == head
  • 当循环队列满队时,tail指针指向的位置实际并没有存储数据。=》循环队列会浪费一个数组的存储空间
 template<class T>
 class SeqQueue{
      protected:
         T *element;
         int front,rear;
         int maxSize;
     public:
         SeqQueue(int sz=10){
             front=rear=0;
             maxSize=sz;
             element=new T[maxSize];
         }
         ~SeqQueue(){
             delete[] element;
         }
         bool EnQueue(const T& x){//入队 
             if(isFull()) return false;
             element[rear]=x;
             rear=(rear+1)%maxSize;
             return true;
         }
         bool DeQueue(T& x){//出队 
             if(isEmpty()) return false;
             x=element[front];
             front=(front+1)%maxSize;
             return true;
         }
         bool getFront(T& x){//获取队首元素 
             if(isEmpty()) return false;
             x=element[front];
             return true;
         }
         void makeEmpty(){//队列置空 
             front=rear=0;
         }
         bool isEmpty()const{//判断队列是否为空 
             return (rear==front)?true:false;
         }
         bool isFull()const{//队列是否为满
              return ((rear+1)%maxSize==front)?true:false;
         }
         int getSize()const{
             return (rear-front+maxSize)%maxSize;
         }
 }; 

4、阻塞队列

支持阻塞操作的队列。具体来讲,支持阻塞添加和阻塞移除。

阻塞添加: 当队列满的时候,队列会阻塞插入插入的元素的线程,直到队列不满;
阻塞移除: 在队列为空时,队里会阻塞插入元素的线程,直到队列不满。

阻塞队列常用于“生产者-消费者模型”,生产者是向队列添加元素的线程;消费者是从队列取元素的线程。

5、并发队列

并发队列就是队列的操作多线程安全。
实现:基于数组的循环队列,利用CAS原子操作,可以实现非常高效的并发队列

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值