自己实现了一个链式循环队列(带头结点的),复习巩固队列与循环链表的知识吧。实现函数有:插入、删除、判断是否为空三个方法(链式存储结构就不太在意为满的情况了,因为内存是动态申请的)。其实链式循环队列,本质还是实现循环链表,只是加了队列的头尾指针,然后多了需要判断队列是否为空,而判断是否为空,在删除函数DeleteQ中有一个很关键的地方:
Position p=Q->Front->Next; //用p前驱,为了后续释放空间方便
Q->Front->Next=p->Next; //修改Front指针的下一个结点
if(Q->Rear==p)
Q->Rear=Q->Front; //当删除到最后一个元素时,由于,我实现的是带头结点的队列,队列的头指针Front始终在head这个头结点上,在删除操作过程中,Rear指针一直在Front指针前面(如图),所以,在删除最后一个元素之后,想要确保队列能达到空,必须将Rear指针也回到head结点上,这样,判断是否为空才能实现
代码如下:
/*
JunWei-Huang
循环队列的链式存储实现
想要达到循环,本质还是实现“链表的循环”即可,只是在循环链表上,加了两个头尾指针,然后“插入”、“删除”操作受限而已
最后修改时间:2023-11-10
*/
#include<stdio.h>
#include<stdlib.h>
#define MAX 10 //链式的有没有最大值无所谓,可以不用管大小,内存是可以任意的
#define ERROR -9999
typedef int ElementType;
typedef struct Node * PtrToNode;
struct Node{
ElementType Data;
PtrToNode Next;
};
typedef PtrToNode Position;
typedef struct QNode* PtrToQNode;
struct QNode{
Position Front,Rear;
};
typedef PtrToQNode Queue;
Queue CreateQueue(int MaxSize);
bool IsFull(Queue Q);
bool AddQ(Queue Q,ElementType X);
bool IsEmpty(Queue Q);
ElementType DeleteQ(Queue Q);
/* 1.带头结点的链式队列实现*/
int main(){
//通过创建一个队列,然后输入一段数据,输出一段数据来实现各个操作集
int qSize,i,data;
Queue qs=CreateQueue(MAX);
printf("请输入你想要入队的元素个数qSize:");
scanf("%d",&qSize);
for(i=1;i<=qSize;i++){//创建队列(入队操作)
printf("请输入第%d个队列元素data:",i);
scanf("%d",&data);
AddQ(qs,data);
}
//手动控制出队数
ElementType d;
int n;
printf("请输入你这次想要出队的个数n:");
scanf("%d",&n);
for(i=1;i<=n;i++){//打印队列(出队操作)
d= DeleteQ(qs);
if(d==ERROR){
printf("队列已空\n");
break;
}
printf("第%d个队列元素是:%d\n",i,d);
}
//程序结束了,把所有开辟出来的结点释放掉
while(DeleteQ(qs)!=ERROR);
return 0;
}
Queue CreateQueue(int MaxSize){//创建一个空的“带头结点的”循环链式队列
Position head=(Position)malloc(sizeof(struct Node));//创建一个空的结点作为头结点
head->Next=head; //头结点Next指向自己,这样,循环链表的初始化就完成了!
Queue q=(Queue)malloc(sizeof(struct QNode));//创建好头尾指针
//循环链表已经完成了,接下来,只需要把头尾指针指向即可
q->Front=head;
q->Front=q->Rear; //让头尾指针指向头结点
// q->MaxSize=MaxSize; 链式实现不用设置最大值
return q;
}
bool IsFull(Queue Q){//链式循环队列就不必实现判断满的方法了
}
bool AddQ(Queue Q,ElementType X){//入队操作
// if(IsFull(Q))
// return false;
//不管三七二十一,先把要入队的结点创建好
Position s=(Position)malloc(sizeof(struct Node));
s->Data=X;
//入队,连在尾结点后面
s->Next=Q->Rear->Next;
Q->Rear->Next=s; //把链表连起来,再移动Rear指针
Q->Rear=s;
return true;
}
bool IsEmpty(Queue Q){//判断队列是否为空
//循环链式队列判断为空与顺序队列的一样(即个两指针都指向head结点,而head结点自己指向自己),就是:
return (Q->Rear==Q->Front);
}
ElementType DeleteQ(Queue Q){//出队操作
if(IsEmpty(Q))
return ERROR;
Position p=Q->Front->Next;
Q->Front->Next=p->Next;
if(Q->Rear==p)
Q->Rear=Q->Front; //这句话非常重要,因为出队,到了最后一个元素,要让尾指针Rear回到头指针的位置,不然出队了永远不会判断对队列是否为空
ElementType x=p->Data;
free(p);
return x;
}