第三章 栈和队列(3.5.3)
目录
3.5.3 链队-队列的链式表示和实现
链队是指采用链式存储结构实现的队列。通常链队用单链表来表示,如图所示。一个链队显然需要两个分别指示队头和队尾的指
针(分别称为头指针和尾指针)才能唯一确定。这里和线性表的单链表一样,为了操作方便起见,给链队添加一个头结点,并令头指针始终指向头结点。
1.队列的链式存储结构的表示
//----单链队列----队列的链式存储结构
typedef struct QNode {
QElemType data;
struct QNode* next;
}QNode, * QueuePtr;
typedef struct {
QueuePtr front;//队头指针
QueuePtr rear;//队尾指针
}LinkQueue;
2.链队操作的实现
2.1.初始化
定义:
链队的初始化操作就是构造一个只有一个头结点的空队
算法步骤:
- 生成新结点作为头结点,队头和队尾指针指向此结点
- 头结点的指针域置空
算法描述
Status InitQueue(LinkQueue &Q)
{
//构造一个空队列
Q.front = Q.rear = new QNode; // 生成新结点作为头结点,队头和队尾指针指向此结点
Q.front->next = NULL; // 头结点指针域置空
return ok;
}
2.2入队
定义:
和循环队列的入队操作不同的是,链队在入队前不需要判断队是否满,需要为入队元素动态分配一个结点空间,如图(b)和(c)所示。
算法步骤:
①为入队元素分配结点空间,用指针p指向。
②将新结点数据域置为e。
③将新结点插入到队尾
④修改队尾指针为p
算法描述:
Status EnQueue(LinkQueue &Q, int e)
{
//插入e为Q的新的队尾元素
QNode *s;
s = new QNode;
if (!s)
{
return 0; //存储分配失败
}
s->data = e;
s->next = NULL;
Q.rear->next = s; // 将新节点插入到队尾
Q.rear = s; //修改尾指针
return 1;
}
3.出队
定义:
和循环队列一样,链队在出队前也需要判断队列是否为空,不同的是,链队在出队后需要释放出队头元素的所占空间,如图(d)所示。
算法步骤:
①判断队列是否为空,若空则返回 ERROR。
②临时保存队头元素的空间,以备释放。
③修改队头指针,指向下一个结点。
④判断出队元素是否为最后一个元素,若是,则将队尾指针重新赋值,指向头结点。
⑤释放原队头元素的空间。
算法描述:
int DeQueue(LinkQueue &Q, int &e)
{
QNode *p;
if (Q.front == Q.rear)
{
return 0;//队列为空
}
p = Q.front->next; // 指针p指向队列的第一个元素
e = p->data;
Q.front->next = p->next; // 修改头结点的指针域
if (Q.rear == p)
{
Q.rear = Q.front;
} // 最后一个元素被删除,队尾指针指向头结点
delete p; // 释放原队头元素所占的空间
return 1;
}
2.4 取队头元素
定义:
与循环队列一样,当队列非空时,此操作返回当前队头元素的值,队头指针保持不变。
算法描述:
int GetHead(LinkQueue Q)
{
// 返回Q的队头元素, 不修改队头指针
if (Q.front != Q.rear) //队列非空
return Q.front->next->data; // 返回队头元素的值,队头指针不变
}
代码
#include <iostream>
#define MAXQSIZE 100
using namespace std;
// 定义顺序队列
typedef struct
{
int *base; //分配存储空间
int front; //队头指针
int rear; //队尾指针
}SqQueue;
//初始化循环队列
int InitQueue(SqQueue &Q)
{
Q.base = new int[MAXQSIZE]; //分配存储空间
if (!Q.base)
return 0; // 存储空间分配失败
Q.front = Q.rear = 0;
return 1;
}
// 求队列的长度
int QueueLength(SqQueue Q)
{
return ((Q.rear - Q.front) + MAXQSIZE) % MAXQSIZE;
}
// 入队操作
int EnQueue(SqQueue &Q, int e)
{
//首先判断队列是否已满
if ((Q.rear + 1) % MAXQSIZE == Q.front)
{
return 0;
}
Q.base[Q.rear] = e; // 新元素插入队尾
Q.rear = (Q.rear + 1) % MAXQSIZE; // 队尾指针加1
return 1;
}
//出队操作
int DeQueue(SqQueue &Q, int &e)
{
if (Q.front == Q.rear)
{
return 0;
}
e = Q.base[Q.front]; // 保存队头元素
Q.front = (Q.front + 1) % MAXQSIZE; // 队头指针加1
return 1;
}
// 取队头元素
int GetHead(SqQueue Q)// 返回Q的队头元素, 不修改队头指针
{
if (Q.front != Q.rear) // 队列非空
return Q.base[Q.front]; // 返回队头元素的值,队头指针不变
}
//遍历队列
void TraveQueue(SqQueue Q)
{
int len = QueueLength(Q);
for (int i = 0; i < len; i++)
{
int e;
DeQueue(Q, e);
printf("%d ", e);
}
}
int main()
{
SqQueue Q;
if (InitQueue(Q))
{
printf("队列初始化成功!\n");
}
else
{
printf("队列初始化失败!\n");
}
printf("队列的初始长度是:%d\n", QueueLength(Q));
// 入队
int n;
printf("请输入队元素的个数:");
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
int e;
printf("请输入第%d个元素的值:", i + 1);
scanf("%d", &e);
EnQueue(Q, e);
}
printf("队列的长度是:%d\n", QueueLength(Q));
printf("遍历队列:");
TraveQueue(Q);
printf("\n队头元素:%d\n", GetHead(Q));
// 出队
for (int i = 0; i < 2; i++)
{
int e;
DeQueue(Q, e);
printf("第%d个出队元素的值:%d\n", i + 1, e);
}
printf("队列的长度是:%d\n", QueueLength(Q));
system("pause");
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构