目录
一、循环队列的定义
循环队列就是将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用。在循环队列结构中,当存储空间的最后一个位置已被使用而再要进入队运算时,只需要存储空间的第一个位置空闲,便可将元素加入到第一个位置,即将存储空间的第一个位置作为队尾。 循环队列可以更简单防止伪溢出的发生,但队列大小是固定的。
在循环队列中,当队列为空时,有front=rear,而当所有队列空间全占满时,也有front=rear。为了区别这两种情况,规定循环队列最多只能有MaxSize-1个队列元素,当循环队列中只剩下一个空存储单元时,队列就已经满了。因此,队列判空的条件是front=rear,而队列判满的条件是front=(rear+1)%MaxSize。
二、循环队列的运算
- 队列的初始化:在循环队列中,我们通常使用一个数组来存储队列中的元素,同时需要维护两个指针:front 和 rear。 front 指向队列的第一个元素,rear 指向队列的最后一个元素的下一个位置(也就是队列的第一个元素的位置)。在队列初始化时,我们需要将 front 和 rear 初始化为 0。
- 入队操作:入队操作就是将元素添加到队列的未尾。在循环队列中,我们只需要将元素添加到 rear 指向的位置,然后将 rear 向后移动一位。如果队列已满,我们需要判断 rear 是否指向 front,如果是,说明队列已经满了,不能添加新元素;如果不是,说明队列还可以继续添加元素。
- 出队操作:出队操作就是从队列的头部删除一个元素。在循环队列中,我们需要将 front 向后移动一位,然后将 front 指向的元素删除。如果队列为空(即 front 和 rear 指向同一个位置),说明不能执行出队操作。
- 队列为空?:判断队列是否为空。在循环队列中,我们可以通过比较 front 和 rear 的值来判断队列是否为空。如果 front 和 rear 指向同一个位置,说明队列为空;
- 队列已满?:判断队列是否已满。在循环队列中,我们可以通过比较 front 和 rear 的值来判断队列已满。如果 rear 指向 front 的前一个位置,说明 队列已满。
- 队列遍历:队列查找就是在队列中查找一个特定的元素。在循环队列中,我们可以从 front 开始向后查找,直到 rear 指向的位置。如果找到了特定的元素,就返回该元素的位置;否则返回-1 表示没有找到该元素。需要注意的是,如果队列为空或没有找到
该元素,返回的结果都是-1。 - 队首:在循环队列中,队首元素位于队列的第一个位置,我们可以通过下标
或者循环队列长度来获取该元素。
三、循环队列的实现
- 队列的定义
/*队列的定义*/
typedef struct
{
DataType data[MAXSIZE];
int front;/*首元素*/
int rear;/*末元素*/
}CirclesQueue;
-
循环队列的初始化
/*循环队列初始化*/
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 isempty(CirclesQueue *Q)
{
return (Q->front == Q->rear) ? 1 : 0;
}
- 获取队首元素
// 获取队首元素
DataType getFront(CirclesQueue *Q) {
int i;
i = (Q -> front) %MAXSIZE;
return Q -> data[(i + 1 % MAXSIZE)];
}
- 队列长度
// 获取队列长度
int getLength(CirclesQueue *Q) {
return (Q->rear - Q->front + MAXSIZE) % MAXSIZE; // 循环队列:若rear在前方,则长度为rear-front+MAXSIZE,否则为rear-front
}
- 遍历队列
// 输出队列内容
int printQueue(CirclesQueue *Q) {
int i;
if (isempty(Q)) {
printf("队列为空,请选择2进行入队\n");
return;
}
i = (Q -> front) %MAXSIZE;
do{
printf(" %d",Q -> data[(i + 1 % MAXSIZE)]);
i = (i+1) %MAXSIZE;
}while(i != Q -> rear);
}
四、完整代码
1.main.c
#include <stdio.h>
#include "CirclesQueue.h"
#include "welcome.h"
int main(int argc, char* argv[])
{
CirclesQueue Q;
DataType x;
int i,d,m,n,cmd;
char yn;
for(i=0;i<strlen(welcome);i++)
{
printf("%c",welcome[i]);
for(m=0;m<1000;m++)
for(n=0;n<1000;n++)
{
;
}
}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:
if(isempty(&Q)){
printf("队列为空!100002\n");
}else{
printf("队列不为空\n");
}
break;
case 5:
if(isfull(&Q)){
printf("队列已满\n");
}else{
printf("队列未满\n");
}
break;
case 6:
printf("队首元素是:【%d】!\n" getFront(&Q));/*获取队首元素*/
break;
case 7:
printf("队列的长度:%d\n"getLength(&Q));/*获取队列长度*/
break;
case 8:
printf("****输出队列****:\n");
printQueue(&Q);
printf("\n");
break;
case 9:
printf("^^^^^^^本程序为顺序栈的演示程序,由林振发设计开发,程序完成了入队、出队、取队首、判断队是否为空、判断队是否满、队列长度等功能!^^^^^^\n");
break;
}
}while(cmd!=0);
return 0;
}
2.CirclesQueue.c
/*
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;
}// 获取队首元素
DataType getFront(CirclesQueue *Q) {
int i;
i = (Q -> front) %MAXSIZE;
return Q -> data[(i + 1 % MAXSIZE)];
}// 获取队列长度
int getLength(CirclesQueue *Q) {
return (Q->rear - Q->front + MAXSIZE) % MAXSIZE; // 循环队列:若rear在前方,则长度为rear-front+MAXSIZE,否则为rear-front
}// 输出队列内容
void printQueue(CirclesQueue *Q) {
int i;
if (isempty(Q)) {
printf("Queue is empty.\n");
return;
}
i = (Q -> front) %MAXSIZE;
do{
printf(" %d",Q -> data[(i + 1 % MAXSIZE)]);
i = (i+1) %MAXSIZE;
}while(i != Q -> rear);
}
3.CirclesQueue.h
#include <stdio.h>
#include "CirclesQueue.h"
#include "welcome.h"
int main(int argc, char* argv[])
{
CirclesQueue Q;
DataType x;
int i,d,m,n,cmd;
char yn;
for(i=0;i<strlen(welcome);i++)
{
printf("%c",welcome[i]);
for(m=0;m<1000;m++)
for(n=0;n<1000;n++)
{
;
}
}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:
if(isempty(&Q)){
printf("队列为空!100002\n");
}else{
printf("队列不为空\n");
}
break;
case 5:
if(isfull(&Q)){
printf("队列已满\n");
}else{
printf("队列未满\n");
}
break;
case 6:
printf("队首元素是:【%d】!\n", getFront(&Q));/*获取队首元素*/
break;
case 7:
printf("队列的长度:%d\n",getLength(&Q));/*获取队列长度*/
break;
case 8:
printf("****输出队列****:\n");
printQueue(&Q);
printf("\n");
break;
case 9:
printf("^^^^^^^本程序为顺序栈的演示程序,由林振发设计开发,程序完成了入队、出队、取队首、判断队是否为空、判断队是否满、队列长度等功能!^^^^^^\n");
break;
}
}while(cmd!=0);
return 0;
}
4.welcome.h
char welcome[]=(
" lovelove lovelove\n"
" lovelovelove lovelovelove\n"
" lovelovelovelove lovelovelovelove\n"
" lovelovelovelovelove lovelovelovelovelove\n"
" lovelovelovelovelovelo lovelovelovelovelovele\n"
" lovelovelovelovelovelovelolovelovelovelovelovelovee\n"
" lovelovelovelovelovelolovellovelovelovelovelovele\n"
" lovelovelovelovelovelovelolovelovelovelovelove\n"
" lovelovelovelovelovelovelovloveloveloveloe\n"
" lovelovelovelovelovelovelovloveloveloe\n"
" lovelovelovelovelolovelovelloveloe\n"
" lovelovelovelovelovelovelovele\n"
" lovelovelovelovelovelocele\n"
" lovelovelovelovelovele\n"
" lovelovelovelovele\n"
" loveloveloveve\n"
" lovelovelo\n"
" lovelov\n"
" love\n"
" 爱\n");
五、运行结果截图
六、总结
循环队列是一种高效、动态且能自我调整的队列结构,特别适用于存储需要频繁插入和删除数据的场景。循环队列是一种数据结构,它可以在固定的空间内实现队列的操作。与普通队列不同的是,循环队列的尾部和头部是相连的,当尾部到达数组的最后一个位置时,它会从数组的第一个位置开始新的插入操作。循环队列有效地解决了普通队列在删除元素时需要移动大量元素的缺点,实现了空间利用率的最大化。
循环队列的实现通常涉及两个指针,一个是 front
指针,指向队列的头部;另一个是 rear
指针,指向队列尾部的前一个位置。在初始化时,两个指针都指向队列的头部。
七、参考文献
- 数据结构c语言版本(李刚)
- 百度查询
- csdn博客
- 课程代码