声明
以下内容仅供学习,如有侵权,联系作者删除。
参考文献:王道考研系列数据结构、B站up主:C语言技术网
链接: C语言技术网
一 队列的基本概念
1.队列的基本定义
队列(Queue):也是一种操作受限的线性表,只允许在表的一端进行插入,而在表的另一端进行删除。
队头(Front):允许删除的一端。
队尾(Rear):允许插入的一端。
空队列:不含任何元素的空表。
2.队列的基本操作
由以下代码给出。
二 队列的顺序存储结构
牺牲一个存储单元的方案:
int front; // 队列的头指针
int rear; // 队列的尾指针,指向队尾的下一个元素
初始化:front = rear = 0;
队空:front == rear
队满:((rear+1) % MAXSIZE) == front
队长:(rear - front +MAXSIZE) % MAXSIZE
1.循环队列代码实现(C语言)
/*
* 程序名:seqqueue1.c,此程序演示循环队列的数组实现,队尾指针指向队尾的下一个元素,没有length的辅助变量。
* 作者:jack 日期:20210617
* 参考作者:C语言技术网(www.freecplus.net), B站UP主:C语言技术网
*/
#include <stdio.h>
#include <string.h>
#define MAXSIZE 10 // 循环队列的最大长度,最多可以存放MAXSIZE-1个元素
typedef int ElemType; // 自定义队列的数据元素为整数
typedef struct Queue
{
ElemType data[MAXSIZE]; // 用数组存储循环队列中的元素
int front; // 队列的头指针
int rear; // 队列的尾指针,指向队尾的下一个元素
}SeqQueue, *PSeqQueue;
// 循环队列QQ的初始化操作
void InitQueue(PSeqQueue QQ);
// 清空循环队列
void ClearQueue(PSeqQueue QQ);
// 销毁循环队列QQ。
void DestroyQueue(PSeqQueue QQ);
// 求循环队列的长度,返回值:>=0-队列QQ元素的个数
int LengthQueue(PSeqQueue QQ);
// 判断循环队列是否为空,返回值:1-空,0-非空或失败。
int IsEmpty(PSeqQueue QQ);
// 判断循环队列是否已满,返回值:1-已满,0-未满或失败。
int IsFull(PSeqQueue QQ);
// 元素入队,返回值:0-失败;1-成功。
int InQueue(PSeqQueue QQ, ElemType *ee);
// 元素出队,返回值:0-失败;1-成功。
int OutQueue(PSeqQueue QQ, ElemType *ee);
// 打印循环队列中全部的元素。
void PrintQueue(PSeqQueue QQ);
// 获取队头元素,返回值:0-失败;1-成功。
// 只查看队头元素的值,元素不出队。
int GetHead(PSeqQueue QQ, ElemType *ee);
int main()
{
SeqQueue Q; // 创建循环队列
InitQueue(&Q); // 初始化循环队列
ElemType e; // 创建一个数据元素
printf("元素(1、2、3、4、5)入队。\n");
e=1; InQueue(&Q, &e);
e=2; InQueue(&Q, &e);
e=3; InQueue(&Q, &e);
e=4; InQueue(&Q, &e);
e=5; InQueue(&Q, &e);
printf("队列的长度是%d\n",LengthQueue(&Q));
PrintQueue(&Q);
if (OutQueue(&Q,&e)==1) printf("出队的元素值为%d\n",e);
if (OutQueue(&Q,&e)==1) printf("出队的元素值为%d\n",e);
if (OutQueue(&Q,&e)==1) printf("出队的元素值为%d\n",e);
if (OutQueue(&Q,&e)==1) printf("出队的元素值为%d\n",e);
if (OutQueue(&Q,&e)==1) printf("出队的元素值为%d\n",e);
printf("队列的长度是%d\n",LengthQueue(&Q));
PrintQueue(&Q);
printf("元素(11、12、13、14、15)入队。\n");
e=11; InQueue(&Q, &e);
e=12; InQueue(&Q, &e);
e=13; InQueue(&Q, &e);
e=14; InQueue(&Q, &e);
e=15; InQueue(&Q, &e);
printf("队列的长度是%d\n",LengthQueue(&Q));
PrintQueue(&Q);
// 只查看队头元素的值,元素不出队。
if (GetHead(&Q,&e)==1) printf("队头的元素值为%d\n",e);
return 0;
}
// 初始化循环队列
void InitQueue(PSeqQueue QQ)
{
ClearQueue(QQ);
}
// 清空循环队列
void ClearQueue(PSeqQueue QQ)
{
if (QQ == NULL) return; // 检查空指针
memset(QQ->data, 0, sizeof(ElemType)*MAXSIZE); // 数组元素清零
QQ->front = QQ->rear = 0;
}
// 销毁循环队列QQ。
void DestroyQueue(PSeqQueue QQ)
{
// 静态循环队列无需释放内存,不需要销毁操作
ClearQueue(QQ); // 清空循环队列
}
// 求循环队列的长度,返回值:>=0-队列QQ元素的个数
int LengthQueue(PSeqQueue QQ)
{
if (QQ == NULL) return 0; // 检查空指针
return (QQ->rear - QQ->front + MAXSIZE)%MAXSIZE;
}
// 判断循环队列是否为空,返回值:1-空,0-非空或失败。
int IsEmpty(PSeqQueue QQ)
{
if (QQ == NULL) return 0; // 检查空指针
if (QQ->front == QQ->rear) return 1;
return 0;
}
// 判断循环队列是否已满,返回值:1-已满,0-未满或失败。
int IsFull(PSeqQueue QQ)
{
if (QQ == NULL) return 0; // 检查空指针
if( ((QQ->rear+1)%MAXSIZE) == QQ->front ) return 1;
return 0;
}
// 元素入队,返回值:0-失败;1-成功
int InQueue(PSeqQueue QQ, ElemType *ee)
{
if ((QQ == NULL) || (ee == NULL)) return 0; // 检查空指针
if (IsFull(QQ) == 1) { printf("循环队列已满,不能插入。\n"); return 0; }
memcpy(QQ->data+QQ->rear, ee, sizeof(ElemType));
QQ->rear = (QQ->rear+1)%MAXSIZE;
return 1;
}
// 元素出队,返回值:0-失败;1-成功
int OutQueue(PSeqQueue QQ, ElemType *ee)
{
if ((QQ == NULL) || (ee == NULL)) return 0; // 检查空指针
if (IsEmpty(QQ) == 1) { printf("队列为空。\n"); return 0; }
memcpy(ee, QQ->data+QQ->front, sizeof(ElemType)); // 采用指针运算
QQ->front = (QQ->front+1)%MAXSIZE; // 队列头指针后移
return 1;
}
// 打印循环队列中全部的元素
void PrintQueue(PSeqQueue QQ)
{
if (QQ == NULL) return; // 检查空指针
if (IsEmpty(QQ) == 1) { printf("队列为空。\n"); return; }
int kk;
for (kk = 0; kk < LengthQueue(QQ); kk++)
{
// 用数组的下标访问。
printf("data[%d],value=%d\n",(QQ->front+kk)%MAXSIZE,QQ->data[(QQ->front+kk)%MAXSIZE]);
// 采用指针运算也可以。
// printf("data[%d],value=%d\n",(QQ->front+kk)%MAXSIZE,*(QQ->data+(QQ->front+kk)%MAXSIZE));
}
}
// 获取队头元素,返回值:0-失败;1-成功
// 只查看队头元素的值,元素不出队
int GetHead(PSeqQueue QQ, ElemType *ee)
{
if ( (QQ == NULL) || (ee == NULL) ) return 0; // 检查空指针
if (IsEmpty(QQ) == 1) { printf("队列为空。\n"); return 0; }
memcpy(ee,&QQ->data[QQ->front],sizeof(ElemType)); // 用数组的下标访问
// memcpy(ee,QQ->data+QQ->front,sizeof(ElemType)); // 采用指针运算
return 1;
}
顺序存储运行结果如下:
三 队列的链式存储结构
1.代码实现(C语言)
/*
* 程序名:linkqueue1.c,此程序演示队列的链表实现(带头结点)
* 作者:jack 日期:20210617
* 参考作者:C语言技术网(www.freecplus.net), B站UP主:C语言技术网
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSIZE 10
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode;
typedef struct
{
LNode *front, *rear;
}LinkQueue, *PLinkQueue;
// 队列QQ的初始化操作
int InitQueue(PLinkQueue QQ);
// 清空队列
void ClearQueue(PLinkQueue QQ);
// 销毁队列QQ。
void DestroyQueue(PLinkQueue QQ);
// 求队列的长度,返回值:>=0-队列QQ元素的个数
int LengthQueue(PLinkQueue QQ);
// 判断队列是否为空,返回值:1-空,0-非空或失败。
int IsEmpty(PLinkQueue QQ);
// 判断队列是否已满,返回值:1-已满,0-未满或失败。
int IsFull(PLinkQueue QQ);
// 元素入队,返回值:0-失败;1-成功。
int InQueue(PLinkQueue QQ, ElemType *ee);
// 元素出队,返回值:0-失败;1-成功。
int OutQueue(PLinkQueue QQ, ElemType *ee);
// 打印队列中全部的元素。
void PrintQueue(PLinkQueue QQ);
// 获取队头元素,返回值:0-失败;1-成功。
// 只查看队头元素的值,元素不出队。
int GetHead(PLinkQueue QQ, ElemType *ee);
int main()
{
LinkQueue Q; // 创建队列
memset(&Q,0,sizeof(LinkQueue));
InitQueue(&Q);
ElemType e; // 创建一个数据元素
printf("元素(1、2、3、4、5)入队。\n");
e=1; InQueue(&Q, &e);
e=2; InQueue(&Q, &e);
e=3; InQueue(&Q, &e);
e=4; InQueue(&Q, &e);
e=5; InQueue(&Q, &e);
printf("队列的长度是%d\n",LengthQueue(&Q));
PrintQueue(&Q);
if (OutQueue(&Q,&e)==1) printf("出队的元素值为%d\n",e);
if (OutQueue(&Q,&e)==1) printf("出队的元素值为%d\n",e);
if (OutQueue(&Q,&e)==1) printf("出队的元素值为%d\n",e);
if (OutQueue(&Q,&e)==1) printf("出队的元素值为%d\n",e);
if (OutQueue(&Q,&e)==1) printf("出队的元素值为%d\n",e);
printf("队列的长度是%d\n",LengthQueue(&Q));
PrintQueue(&Q);
printf("元素(11、12、13、14、15)入队。\n");
e=11; InQueue(&Q, &e);
e=12; InQueue(&Q, &e);
e=13; InQueue(&Q, &e);
e=14; InQueue(&Q, &e);
e=15; InQueue(&Q, &e);
printf("队列的长度是%d\n",LengthQueue(&Q));
PrintQueue(&Q);
// 只查看队头元素的值,元素不出队。
if (GetHead(&Q,&e)==1) printf("队头的元素值为%d\n",e);
return 0;
}
// 初始化队列,返回值:0-失败;1-成功
int InitQueue(PLinkQueue QQ)
{
LNode *head = (LNode *)malloc(sizeof(LNode)); // 分配头结点
if (head == NULL) return 0; // 内存不足,返回失败
head->next = NULL; // 头结点的下一结点暂时不存在,置空
QQ->front = QQ->rear = head;
return 1;
}
// 清空队列
void ClearQueue(PLinkQueue QQ)
{
if (QQ == NULL) return; // 检查空指针
if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return; } // 队列未初始化
// 清空队列QQ是指释放链表全部的数据结点,但保留头结点
LNode *tmp = QQ->front->next;
LNode *tmpnext;
while(tmp != NULL)
{
tmpnext = tmp->next; // tmpnext保存下一结点的地址
free(tmp); // 释放当前结点。
tmp = tmpnext; // tmp指针移动到下一结点
}
QQ->rear=QQ->front; // 尾指针指向头结点
QQ->front->next=NULL;
}
// 销毁队列QQ。
void DestroyQueue(PLinkQueue QQ)
{
if (QQ == NULL) return; // 检查空指针
if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return; } // 队列未初始化
// 清空队列QQ是指释放链表全部的数据结点,但保留头结点
LNode *tmp = QQ->front;
LNode *tmpnext;
while(tmp != NULL)
{
tmpnext = tmp->next; // tmpnext保存下一结点的地址
free(tmp); // 释放当前结点。
tmp = tmpnext; // tmp指针移动到下一结点
}
QQ->rear=QQ->front=NULL; // 防止野指针
return;
}
// 求队列的长度,返回值:>=0-队列QQ元素的个数
int LengthQueue(PLinkQueue QQ)
{
if (QQ == NULL) return 0; // 检查空指针
if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return 0; } // 队列未初始化
LNode *tmp = QQ->front->next; // 头结点不算,从第1个结点开始
int length = 0;
while(tmp != NULL)
{
length++;
tmp = tmp->next;
}
return length;
}
// 判断队列是否为空,返回值:1-空,0-非空或失败。
int IsEmpty(PLinkQueue QQ)
{
if (QQ == NULL) return 0; // 检查空指针
if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return 0; } // 队列未初始化
if (QQ->front->next == NULL) return 1;
return 0;
}
// 判断队列是否已满,链式队列不存在队满的说法
int IsFull(PLinkQueue QQ)
{
if (QQ == NULL) return 0; // 检查空指针
return 0;
}
// 元素入队,返回值:0-失败;1-成功
int InQueue(PLinkQueue QQ, ElemType *ee)
{
if ((QQ == NULL) || (ee == NULL)) return 0; // 检查空指针
if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return 0; } // 队列未初始化
LNode *tmp = (LNode *)malloc(sizeof(LNode));
if (tmp == NULL) return 0;
memcpy(&tmp->data, ee, sizeof(ElemType));
tmp->next = NULL;
QQ->rear->next = tmp;
QQ->rear = tmp;
return 1;
}
// 元素出队,返回值:0-失败;1-成功
int OutQueue(PLinkQueue QQ, ElemType *ee)
{
if ((QQ == NULL) || (ee == NULL)) return 0; // 检查空指针
if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return 0; } // 队列未初始化
if (IsEmpty(QQ) == 1) { printf("队列为空。\n"); return 0; }
LNode *tmp = QQ->front->next;
memcpy(ee, &tmp->data, sizeof(ElemType)); // 采用指针运算
QQ->front->next = tmp->next; // 队列头指针后移
// 如果出队的是最后一个结点。
if (QQ->rear==tmp) QQ->rear=QQ->front;
free(tmp);
return 1;
}
// 打印队列中全部的元素
void PrintQueue(PLinkQueue QQ)
{
if (QQ == NULL) return; // 检查空指针
if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return; } // 队列未初始化
LNode *pp = QQ->front->next;
while(pp != NULL)
{
printf("%-3d", pp->data); // 如果元素ee为结构体,这行代码要修改
pp = pp->next;
}
printf("\n");
}
// 获取队头元素,返回值:0-失败;1-成功
// 只查看队头元素的值,元素不出队
int GetHead(PLinkQueue QQ, ElemType *ee)
{
if ( (QQ == NULL) || (ee == NULL) ) return 0; // 检查空指针
if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return 0; } // 队列未初始化
if (IsEmpty(QQ) == 1) { printf("队列为空。\n"); return 0; }
memcpy(ee,&QQ->front->next->data,sizeof(ElemType));
return 1;
}
链式存储运行结果如下:
四 小结
1.栈和队列都已经介绍完毕,接下来介绍栈和队列的应用。