数据结构之队列(C/C++实现)

定义

  • 队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表
  • 队列是一种先进先出的线性表(FIFO),允许插入的一端称为队尾,允许删除的一端称为队头

队列的抽象数据类型

ADT 队列(Queue)
Data
    同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系
Operation
    InitQueue(*Q):    初始化操作,建立一个空队列Q
    DestroyQueue(*Q):   若队列Q存在,则销毁它
    ClearQueue(*Q):  将队列Q清空
    QueueEmpty(Q):   若队列为空,返回true,否则返回false
    GetHead(Q,*e):  若队列存在且非空,用e返回队列Q的队头元素。
    EnQueue(*Q,e): 若队列Q存在,插入新元素e到队列Q中并称为队尾元素
    DeQueue(*Q,*e):  删除队列Q中的队头元素,并用e返回其值
    QueueLength(Q):   返回队列Q的元素个数
endADT

循环队列

  • 队列顺序储存,引入两个指针front和rear。front指针指向队头元素,rear指针指向队尾元素的下一个位置,这样当front等于rear时,队列为空。
  • 队列的顺序存储会出现假溢出现象
  • 为了解决假溢出现象,我们引入循环队列。我们把队列这种头尾相连的顺序存储结构称为循环队列

循环队列为空的时候为front等于rear 循环队列满的时候front也等于rear。
那么如何判断此队列究竟是空还是满呢?

  • 设置一个标志变量flag,当front == rear,且flag=0时队列为空,当front==rear,且flag=1时队列满
  • 当队列空时,条件就是front==rear,当队列满时,我们修改其条件,保留一个元素空间。也就是说,队列满时,数组中还有一个空闲单元。

针对第二种情况:

  • 队列满的条件是(rear+1)%QueueSize == front
  • 队列长度计算公式(rear-front+QueueSize)% QueueSize
#define MAXSIZE 50
#define OK 1
#define ERROR 0
#define True 1
#define False 0
typedef int Status;/*函数的返回类型,这里定义为int*/
typedef int QElemType;/*SElemType根据情况来顶,这里假设为int*/

typedef struct
{
    QElemType data[MAXSIZE];
    int front;      //头指针
    int rear;       //尾指针,若队列不为空,指向队列元素的下一个位置
}SqQueue;

循环队列的初始化:

//初始化一个空队列
Status InitQueue(SqQueue *Q)
{
    Q->front=0;
    Q->rear=0;
    return OK;
}

循环队列求队列长度

//返回Q的元素个数,也就是队列的长度
int QueueLength(SqQueue Q)
{
    return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}

循环队列的入队操作

//若队列未满,插入元素e为Q新的队列元素
Status EnQueue(SqQueue *Q,QElemType e)
{
    if((Q->rear+1)%MAXSIZE==Q->front)  /*队列满的判断*/
    {
        return ERROR;
    }
    Q->data[Q->rear]=e;      //将元素e赋值给队列
    Q->rear=(Q->rear+1)%MAXSIZE;   //rear指针向后移动一个位置,若到最后则转到数组头部
    return OK;
}

循环队列的出队操作:

//若队列不空,则删除Q中的队头元素,用e返回其值
Status DeQueue(SqQueue *Q,QElemType *e)
{
    if(Q->front==Q->rear)
    {
        return ERROR;
    }
    *e=Q->data[Q->front];    //将队头元素赋值给e
    Q->front=(Q->front+1)%MAXSIZE;   //front指针向后移一位,若到最后则转到数组头部
    return OK;
}

队列的链式存储结构及实现

队头指针指向链队列的头节点
队尾指针指向链队列的尾节点
空队列时,front和rear都指向头节点。
链队列的结构:

typedef struct QNode   /*结点结构*/
{
    QElemType data;
    struct QNode *next;
}QNode,*QueuePtr;

typedef struct      /*队列的链表结构*/
{
    QueuePtr front,rear;    /*队头,队尾指针*/
}LinkQueue;

入队操作:

/*插入元素e为Q的新的队尾元素*/
Status EnQueue(LinkQueue *Q,QElemType e)
{
    QueuePtr s=(QueuePtr)malloc(sizeof (QNode));
    if(!s)      /*存储分配失败*/
    {
        exit(1);
    }
    s->data=e;
    s->next=nullptr;
    Q->rear->next=s;    //把拥有元素e新节点s赋值给原队尾节点的后继
    Q->rear=s;        //把当前的s设置成队尾节点,rear指向s
    return OK;
}

出队操作:

/*若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR*/
Status DeQueue(LinkQueue *Q,QElemType *e)
{
    QueuePtr p;
    if(Q->front==Q->rear)
    {
        return ERROR;
    }
    p=Q->front->next;  //将欲删除的队头结点暂存给p
    *e=p->data;        //将欲删除的队头结点的值赋给e
    Q->front->next=p->next;   //将原队头节点后继p->next赋值给头节点后继
    if(Q->rear==p)          //若队头是队尾,则删除后将rear指向头节点
    {
        Q->rear=Q->front;
    }
    free(p);
    return OK;
}

循环队列的C++实现

#include <iostream>
using namespace std;
class queue
{
public:
    queue(int items);//参数items为打算存放的数据量
    virtual ~queue();
    bool EnQueue(int data);
    bool DeQueue(int* pRecvData=nullptr);
    void DeTraverse();//遍历队列中存储的数据元素
    int GetSize();//获取队列中的数据量
    bool IsFull();
    bool IsEmpty();
private:
    int* pArr;
    int head,tail;
    int length;//队列的实际长度
};

queue::queue(int items)
{
    this->length = items + 1;//必须多开辟一个空间,因为尾指针要指向这个空间
    pArr = new int[this->length];
    head = tail = 0;
}

queue::~queue()
{
    delete[]pArr;
}

bool queue::EnQueue(int data)
{
    if (IsFull())
    {
        cout<<"队列已满!"<<endl;
        return false;
    }
    pArr[tail] = data;
    tail = (tail + 1) % length;
    return true;
}

bool queue::DeQueue(int* pRecvData)
{
    if (IsEmpty())
    {
        cout << "队列为空!" << endl;
        return false;
    }
    if (pRecvData != nullptr)
        *pRecvData = pArr[head];
    head = (head+1) % length;
    return true;
}

int queue::GetSize()
{
    return (tail - head + length) % length;
}

bool queue::IsFull()
{
    return (tail + 1) % length == head;
}

bool queue::IsEmpty()
{
    return head == tail;
}

void queue::DeTraverse()
{
    if (head == tail)
    {
        cout << "队列为空!" << endl;
        return;
    }
    for (int i = head; i != tail; i = (i + 1) % length)
        cout << pArr[i] << " ";
    cout << endl;
}
int main()
{
    queue que(5);
    cout<<"que的数据量为:" <<que.GetSize()<< endl;
    que.EnQueue(1);
    que.EnQueue(2);
    que.EnQueue(3);
    que.EnQueue(4);
    que.EnQueue(5);
    que.DeQueue();
    que.EnQueue(6);
    cout << "que的数据量为:" << que.GetSize() << endl;
    que.DeTraverse();
    getchar();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值