C语言数据结构--队列
- 基本概念
- 链队列
-
- 原理
- 基本操作
-
- 队列的链式存储结构
- 初始化队列InitQueue
- 入队列EnQueue
- 出队列DeQueue
- 销毁队列
- 输出队列元素
- 链队列基本操作代码
- 循环队列
-
- 原理
- 基操
-
- 初始化循环队列InitQueue
- 入队列EnQueue
- 出队列DeQueue
- 求栈长度QueueLength
- 输出队列元素display
- 完整程序
基本概念
队列是一种 先进先出(FIFO)的线性表
顾名思义,就和排队一样,先加入队伍的人先离开队伍,后加入队伍的人后离开队伍
队列只允许在队尾插入元素,在队头删除元素
既然队列是线性表的一种,那么肯定也有两种存储形式
链队列 ——链式映像
循环队列——顺序映像
栈一般使用顺序表来实现,队列一般使用链表实现,即链队列
链队列
原理
用链表表示的队列简称为链队列
一个链队列需要两个分别指示对头和队尾的阵阵才能唯一确定。
基本操作
队列的链式存储结构
#include <>
#include <>
#include <>
#define ERROR -1;
#define OK 1;
typedef char QElemType;
typedef struct QNode{
//结点类型
QElemType data; //队列中结点的数据域
struct QNode *next;//结点的指针域
}QNode,*QueuePtr;
typedef struct{
//链队列类型
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
注意,我们队头指针指向链队列的头结点,队尾指针指向终端结点(虽然头结点不是必须,但为了方便操作,我们一般加上头结点)
初始化队列InitQueue
示意图:
代码
LinkQueue *InitQueue(){
LinkQueue *Q = (LinkQueue *)malloc(sizeof(LinkQueue));
Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));
Q->front->next = NULL;
printf("初始化队列成功!\n");
return Q;
}
入队列EnQueue
入队列是从队尾插入元素,就像排队,肯定是从队尾排队。
如何找到队尾呢?
这就要用到队尾指针了。
示意图:
代码
/**
* 入队列
* 1. 创建一个新结点分配内存
* 2. 初始化新结点
* 3. 插入新结点并移动队尾指针
*/
Status EnQueue(LinkQueue *Q, QElemType *e) {
//创建一个新结点并分配内存
QueuePtr T = (QueuePtr)malloc(sizeof(QNode));
if(!T){
printf("分配内存失败!");
exit(OVERFLOW);
}
//初始化新结点
T->data = e;
T->next = NULL;
//插入新结点并移动队尾指针
Q->rear->next = T;
Q->rear = T;
return OK;
}
注意
⭐⭐⭐⭐⭐
代码里有一段代码
Q->rear->next = T;//将新元素插入到队列末尾
Q->rear = T;//队尾指针移动位置
我刚开始直接使用 Q->rear = p;错过了前面一步。前面的一步是必不可少的。
因为第一步代码是先将队列插入,第二步是移动队尾指针位置,两者并不重复。都很重要。
出队列DeQueue
思考思路:
1)判断是否为空队列
2)出队列即从队头删除元素,是不是似曾相识的感觉,没错,出栈和出队列的原理几乎相同。
示意图:
程序
/**
* 出队列
* 1. 判断队列是否为空
* 2. 删除队首元素
* 3. 如果刚刚删除的是最后一个元素,将该队列置空
* 4. 释放空间
*/
Status DeQueue(LinkQueue *Q, QElemType *e){
QueuePtr p;
//判断队列是否为空
if(Q->front == Q->rear) {
printf("队列为空!");
exit(OVERFLOW);
}
//删除队首元素
p = Q->front->next;
*e = p->data;
Q->front->next = p->next;
//如果刚刚删除的是最后一个元素,将该队列置空
if(Q->rear == p){
Q->rear = Q->front;//这里无所谓顺序,也可以写成 Q->front = Q->rear
}
free(q);
retu