数据结构之循环队列
一、循环队列
1.定义
循环队列(Circular Queue)是一种使用静态数组实现的队列,它允许在队列的头部和尾部进行插入和删除操作。循环队列在表现上像是一个固定大小的数组,但实际上它使用一个指针来指示队列的头部和尾部。当尾部指针到达数组的末端时,它会从数组的开始处继续。循环队列有效地利用了数组的空间,避免了普通队列中因为头尾指针不断移动而浪费的空间。
2.两个关键的指针
- front:指向队列的头部元素。
- rear:指向队列尾部元素的下一个位置。当元素被添加到队列中时,rear 会向前移动一位。
3.两种特殊情况
- 当 rear 到达数组的末端时,需要将 rear 重新指向数组的开始。
- 当 front 到达数组的末端时,需要将 front 重新指向数组的开始。
循环队列可以有效地处理队列满和队列空的情况。在普通队列中,当队列满时,最后一个元素之后将没有空间添加新元素,导致队列溢出。但在循环队列中,当 rear 到达数组的末端时,它将自动回到数组的开始,从而为添加新元素腾出空间。同样,当 front 和 rear 相遇时,意味着队列为空。
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
4.优点
- 有效地利用了数组空间,避免了普通队列中因为头尾指针不断移动而浪费的空间。
- 循环队列通过在尾部添加新元素和头部删除元素的方式,使得队列操作具有连续性,减少了因删除元素导致的大量移动操作。
- 循环队列可以动态地扩展队列容量,避免了普通队列中因固定容量导致的空间浪费或溢出问题。
5.缺点
- 需要在实现时额外维护一个记录队列长度的变量,增加了编程的复杂性。
- 在进行出队操作时,需要比较头尾指针的位置关系,增加了判断操作的时间开销。
- 在进行入队操作时,需要比较队列长度和队列容量的大小关系,增加了比较操作的时间开销。
- 在循环队列实现中,如果未处理入队和出队时头尾指针位置相同的特殊情况,会导致错误的判断队列为空或已满的条件。
二、代码及运行
1.初始化
int init(CirclesQueue *Q)
{
Q->front = Q->rear = 0;
return 0;
}
2.入队
int enqueue(CirclesQueue *Q, DataType x)
{
if(isfull(Q))
{
printf("队列已满!100001\n");
return 100001;
}
Q->rear = (Q->rear+1) % MAXSIZE;
Q->data[Q->rear] = x;
return 0;
}
3.出队
int dequeue(CirclesQueue *Q, DataType *x)
{
if(isempty(Q))
{
printf("队列为空!100002\n");
return 100002;
}
Q->front = (Q->front+1) % MAXSIZE;
*x = Q->data[Q->front];
return 0;
}
4.输出队列
void print(CirclesQueue *Q)
{
int i;
if(isempty (Q))
{
print("队列为空!\n");
return;
}
i=(Q->front)% MAXSIZE;
do
{
printf("%d",Q->data[(i+1)% MAXSIZE]);
i=(i+1)% MAXSIZE;
}while(i!=Q->rear);
}
5.取队头元素
int printw(CirclesQueue *Q )
{
return Q->data[Q->front +1 %MAXSIZE];
}
6.队列长度
int length(CirclesQueue *Q)
{
return Q->rear-Q->front +MAXSIZE%MAXSIZE;
}
7.队满?
if(isfull(&Q))
{
printf("队列已满!100001\n");
}else
printf("队列未满");
8.队空?
if(isempty(&Q))
{
printf("队列为空!100002\n");
}else
printf("队列不为空");
9.帮助
printf("感谢季老师对我的关心和支持,让我在学习过程中充满信心和动力");
三、整体代码
- main.c
#include <stdio.h>
#include "CirclesQueue.h"
int main(int argc, char* argv[])
{
CirclesQueue Q;
DataType x;
int cmd;
char yn;
do
{
printf("-----------循环队列演示-----------\n");
printf(" 1. 初始化\n");
printf(" 2. 入队\n");
printf(" 3. 出队\n");
printf(" 4. 输出队列\n");
printf(" 5. 取队头元素\n");
printf(" 6. 队列长度\n");
printf(" 7. 队满?\n");
printf(" 8. 队空?\n");
printf(" 9. 帮助\n");
printf(" 0. 退出\n");
printf(" 请选择(0~6):");
scanf("%d",&cmd);
switch(cmd)
{
case 1:
init(&Q);
printf("队列已初始化!\n");
break;
case 2:
printf("请输入要入队的元素x=");
scanf("%d", &x);
if(!enqueue(&Q,x))
{
printf("元素x=%d已入队\n", x);
}
break;
case 3:
printf("确定要出队(出队会将删除对首元素, y or n, n)?");
flushall();
scanf("%c", &yn);
if(yn == 'y' || yn == 'Y')
{
if(!dequeue(&Q,&x))
{
printf("队首元素【%d】已出队!\n", x);
}
}
break;
case 4:
print(&Q,&x);
break;
case 5:
printf("%d",printw(&Q));
break;
case 6:
printf("%d",length(&Q));
break;
case 7:
if(isfull(&Q))
{
printf("队列已满!100001\n");
}else
printf("队列未满");
break;
case 8:
if(isempty(&Q))
{
printf("队列为空!100002\n");
}else
printf("队列不为空");
break;
case 9:
printf("感谢季老师对我的关心和支持,让我在学习过程中充满信心和动力");
break;
}
}while(cmd!=0);
return 0;
}
- CirclesQueue.c
#include "CirclesQueue.h"
/*循环队列初始化*/
int init(CirclesQueue *Q)
{
Q->front = Q->rear = 0;
return 0;
}
/*入队*/
int enqueue(CirclesQueue *Q, DataType x)
{
if(isfull(Q))
{
printf("队列已满!100001\n");
return 100001;
}
Q->rear = (Q->rear+1) % MAXSIZE;
Q->data[Q->rear] = x;
return 0;
}
/*队满?*/
int isfull(CirclesQueue *Q)
{
return (Q->rear+1)%MAXSIZE == Q->front ? 1 : 0;
}
/*出队*/
int dequeue(CirclesQueue *Q, DataType *x)
{
if(isempty(Q))
{
printf("队列为空!100002\n");
return 100002;
}
Q->front = (Q->front+1) % MAXSIZE;
*x = Q->data[Q->front];
return 0;
}
/*队空*/
int isempty(CirclesQueue *Q)
{
return (Q->front == Q->rear) ? 1 : 0;
}
/*输出队列*/
void print(CirclesQueue *Q)
{
int i;
if(isempty (Q))
{
print("队列为空!\n");
return;
}
i=(Q->front)% MAXSIZE;
do
{
printf("%d",Q->data[(i+1)% MAXSIZE]);
i=(i+1)% MAXSIZE;
}while(i!=Q->rear);
}
/*取队头*/
int printw(CirclesQueue *Q )
{
return Q->data[Q->front +1 %MAXSIZE];
}
/*队列长度*/
int length(CirclesQueue *Q)
{
return Q->rear-Q->front +MAXSIZE%MAXSIZE;
}
- CirclesQueue.c
int init(CirclesQueue *Q)
{
Q->front = Q->rear = 0;
return 0;
}
/*入队*/
int enqueue(CirclesQueue *Q, DataType x)
{
if(isfull(Q))
{
printf("队列已满!100001\n");
return 100001;
}
Q->rear = (Q->rear+1) % MAXSIZE;
Q->data[Q->rear] = x;
return 0;
}
/*队满?*/
int isfull(CirclesQueue *Q)
{
return (Q->rear+1)%MAXSIZE == Q->front ? 1 : 0;
}
/*出队*/
int dequeue(CirclesQueue *Q, DataType *x)
{
if(isempty(Q))
{
printf("队列为空!100002\n");
return 100002;
}
Q->front = (Q->front+1) % MAXSIZE;
*x = Q->data[Q->front];
return 0;
}
/*队空*/
int isempty(CirclesQueue *Q)
{
return (Q->front == Q->rear) ? 1 : 0;
}
/*输出队列*/
void print(CirclesQueue *Q)
{
int i;
if(isempty (Q))
{
print("队列为空!\n");
return;
}
i=(Q->front)% MAXSIZE;
do
{
printf("%d",Q->data[(i+1)% MAXSIZE]);
i=(i+1)% MAXSIZE;
}while(i!=Q->rear);
}
/*取队头*/
int printw(CirclesQueue *Q )
{
return Q->data[Q->front +1 %MAXSIZE];
}
/*队列长度*/
int length(CirclesQueue *Q)
{
return Q->rear-Q->front +MAXSIZE%MAXSIZE;
}
四、小结
循环队列是数据结构中一个非常经典的概念,相对于其他队列结构,循环队列可以优化存储空间的使用,减少空间的浪费。循环队列的操作也比较高效,能够快速执行入队和出队操作。经过这次的作业,我对循环队列结构进行了深入的了解与实践,更深刻地认识到了数据结构的重要性。