数据结构——队列

形状

队列是一种先进后出的线性表,它允许插入的一端叫队尾,允许删除的一端叫队头

与平时排队一样,从队伍后面排,从队伍前面出。

当多个任务同时运行且需要通过同一个通道输出时,就要按照请求顺序来排队,此时便可使用队列。

在这里插入图片描述

顺序表示(顺序队列)

头指针front始终指向队头,当队列未满时,rear始终指向队尾元素的下一个。

#define MAXQSIZE 100
typedef struct
{
    QElemType *base;//存储空间基地址
    int front;//头指针,int类型,存储队伍头地址
    int rear;//尾指针,int类型,存储队伍尾地址
}SqQueue;

为解决入队出队导致空间有些没用到的问题(如下图所示,经过四次操作后,尾指针已经指向最后一个位置,而前面是空但是因为头指针不能插入了),我们使队列变成一个环形结构,称为循环队列。

在这里插入图片描述

其他与原理一致,只不过在循环队列中头尾指针加一时使用模运算来实现:

  • Q.rear =(Q.rear + 1) % MAXQSIZE
  • Q.front =(Q.front + 1) % MAXQSIZE

判断队满队空:少用一个数据元素(有一个地方始终为空),即m个位置,m-1个元素则算队列满了:

  • 队空 -> Q.rear = Q.front
  • 队满 -> (Q.rear + 1) % MAXQSIZE = Q.front

初始化

Status InitQueue(SqQueue& Q)
{
    Q.base = new SqElemType[MAXQSIZE];//顺序表,需要开辟一段空间
    if (!Q.base) exit(OVERFLOW);//分配失败
    Q.rear = Q.front = 0;//空队列
    return ok;
}

获取长度

int QueueLength(SqQueue Q)
{
	return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;//循环队列可能出现尾减头为负数的情况,所以要加上MAXQSIZE;当为正数加上MAXQSIZE会大于实际大小,则取余MAXQSIZE,得出大小
}

入队

Status EnQueue(SqQueue& Q, QElemType e)
{
    if ((Q.rear + 1)  %  MAXQSIZE == Q.front) return error;//队列已满
    Q.base[Q.rear] = e;//把新元素放入队列
    Q.rear = (Q.rear + 1)  %  MAXQSIZE;//尾指针加一
    return ok;
}

出队

Status DeQueue(SqQueue& Q, QElemType& e)
{
    if (Q.rear == Q.front) return error;//队列为空
    e = Q.base[Q.front];//把元素取出
    Q.front = (Q.front + 1)  %  MAXQSIZE;//头指针加一,队列头出队后,要往后移,地址是增加的
    return ok;
}

取队头元素

QElemType GetHead(SqQueue Q)
{//返回队头元素,不改变头指针
    if(Q.front != Q.rear)//队列非空
        return Q.base[Q.front];
}

链式表示(链队列)

队列的删除插入地方不一样,故而需要两个指针,为了安全和方便操作,使用结构将其封装起来;

所以需要先创造节点结构,再创造链表结构,使链表结构中有整个队列的头尾指针,区分操作;

而栈只在栈顶操作,所以只需要一个指针,在函数内直接定义一个即可串起来全部。

无论是栈还是队列,在链式表示中,在栈底与队列头都需要一个全空的节点作为判断。

#define MAXQSIZE 100
typedef struct QNode
{
    QElemType data;
    struct QNode *next;//存储空间基地址
}QNode, *QueuePtr;

typedef struct
{
    QueuePtr front;//头指针,int类型,存储队伍头地址
    QueuePtr rear;//尾指针,int类型,存储队伍尾地址
}LinkQueue; 

初始化

Status InitQueue(LinkQueue& Q)
{
    Q.front = Q.rear = new QNode;//申请一个头节点
    Q.front->next = NULL;//头指针的next置空
    return ok;
}

在这里插入图片描述

入队

Status EnQueue(LinkQueue& Q, QElemType e)
{//不需要判断队列满没有,因为链表是动态的;下面只改变尾指针是因为头指针只能删除用,故而用尾指针插入
    QNode p = new QNode;//创建一个节点
    p->data = e;
    p->next = NULL;
    Q.rear->next = p;//使新节点插入队尾
    Q.rear = p;//队尾指针指向队尾元素
    return ok;
}

出队

Status DeQueue(LinkQueue& Q, QElemType& e)
{
    if (Q.rear == Q.front) return error;//队列为空
    p = Q.front->next;//用一个新节点代替队头节点,便于等会挪完队头指针后,在内存空间删除它
    e = p->data;
    Q.front->next = p->next;//修改头节点,指向下一个
    if(Q.rear = p) Q.rear = Q.front;//若最后一个元素被删除了,队尾指针指向队头指针
    delete p;
    return ok;
}

取队头元素

QElemType GetHead(LinkQueue Q)
{//返回队头元素,不改变头指针
    if(Q.front != Q.rear)//队列非空
        return Q.front->next->data;
}

在STL中队列的主要操作函数

1.queue<> q

创建一个空队列

queue<队列内数据的类型> q;

2. push()

将元素加入队尾(back)。

queue<int> q;
q.push(10);  // 将 10 加入队尾
q.push(20);  // 将 20 加入队尾

3. pop()

移除队头(front)元素。注意,pop() 不会返回被删除的元素。

q.pop();  // 移除队头元素 10

4. front()

返回队头元素的引用,但不删除它。

int front_element = q.front();  // 获取队头元素,值为 20

5. back()

返回队尾元素的引用,但不删除它。

int back_element = q.back();  // 获取队尾元素,值为 20

6. empty()

检查队列是否为空,若为空则返回 true,否则返回 false

bool is_empty = q.empty();  // 检查队列是否为空

7. size()

返回队列中元素的数量。

size_t count = q.size();  // 队列中的元素数量

示例代码

#include <iostream>
#include <queue>//使用STL需要包含这个头文件
using namespace std;

int main() {
    queue<int> q;
    q.push(1);
    q.push(2);
    q.push(3);

    cout << "队头元素: " << q.front() << endl;  // 输出 1
    cout << "队尾元素: " << q.back() << endl;   // 输出 3

    q.pop();  // 移除队头元素 1

    cout << "移除队头后的新队头: " << q.front() << endl;  // 输出 2
    cout << "队列的大小: " << q.size() << endl;  // 输出 2
    cout << "队列是否为空: " << (q.empty() ? "是" : "否") << endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值