1️⃣:初始化空队列,q -> front = q -> rear = 0
2️⃣:入队a1、a2、a3,q -> front = 0, q -> rear = 3
3️⃣:出队a1、a2,q -> front = 2, q -> rear = 3
4️⃣:入队a4、a5、a6,q -> front = 2, q -> rear = 6
执行 4️⃣ 操作后队列的"尾指针"已经超出对队列的最大范围了,之后无法再进行入队操作,而队列实际空间并未占满,就造成了假溢出。
1、将队中元素依次向队头方向移动。
2、将队列空间设想成一个循环的表,即分配给队列的 m
个存储单元可以循环使用,当 rear
为 MAXSIZE
时,若队列的开始端空着,又可从头使用空着的空间。当 front
为 MAXSIZE
时也是一样。
我们采用第2种方法
5️⃣:入队a7,q -> front = 2, q -> rear = 0
base[0] 接在 base[MAXSIZE -1] 之后,若 rear + 1 == M,则令 rear = 0
实现方法: 利用 模(mod,C语言中: %)运算。
插入元素:
// 队尾入队
q -> base[q -> rear] = data;
// 更新队尾指针
q -> rear = (q -> rear + 1) % MAXSIZE;
删除元素:
// 队头元素出队
data = q -> base[q -> front];
// 更新队头指针
q -> front = (q -> front + 1) % MAXSIZE;
解决方案:
1.另外设一个标致以区别队空、队满
2.另设一个变量,记录元素个数
3.少用一个元素空间
本文实现的方法就是第三种。
/********************* 循环队列的常规操作 **************************/
Queue InitQueue(); // 初始化循环队列
int QueueFull(); // 循环队列判满
int QueueEmpty(); // 循环队列判空
int QueueLength(); // 求循环队列长度(元素个数)
int EnQueue(); // 循环队列 入队
int DeQueue(); // 循环队列 出队
void QueueStatus(); // 打印队满、队空、队长状态
/****************************************************************/
#include "stdio.h"
#include "malloc.h"
#define TRUE 1
#define FALSE 0
#define MAXSIZE 10
typedef int ElemType;
// 定义循环队列结构体
typedef struct Queue{
int *base; // 队列首地址
int front; // 队列头下标
int rear; // 队列尾下标
}*Queue;
/*
* 初始化循环队列
*/
Queue InitQueue(){
Queue q;
// 分配循环队列空间
q -> base = (ElemType *)malloc(sizeof(ElemType) * MAXSIZE);
q -> front = q -> rear = 0;
return q;
}
/*
* 循环队列判满
* q 循环队列
*/
int QueueFull(Queue q){
if(q == NULL){
return FALSE;
}
return (q -> rear + 1) % MAXSIZE == q -> front;
}
/*
* 循环队列判空
* q 循环队列
*/
int QueueEmpty(Queue q){
if(q == NULL){
return FALSE;
}
return q -> front == q -> rear;
}
/*
* 计算循环队列长度
* q 循环队列
*/
int QueueLength(Queue q){
if(q == NULL){
return FALSE;
}
return (q -> rear - q -> front + MAXSIZE) % MAXSIZE;
}
/*
* 循环队列 入队
* q 循环队列
* data 入队元素
*/
int EnQueue(Queue q, ElemType data){
if(QueueFull(q)){
return FALSE;
}
// 队尾入队
q -> base[q -> rear] = data;
// 更新队尾指针
q -> rear = (q -> rear + 1) % MAXSIZE;
return TRUE;
}
/*
* 循环队列 出队
* q 循环队列
* *val 用来存出队元素的数据
*/
int DeQueue(Queue q, ElemType *val){
if(QueueEmpty(q)){
return FALSE;
}
// 队头元素出队
*val = q -> base[q -> front];
// 更新队头指针
q -> front = (q -> front + 1) % MAXSIZE;
return TRUE;
}
/*
* 打印队满、队空、队长状态
* q 循环队列
*/
void QueueStatus(Queue q){
printf("QueueFull():%d\n", QueueFull(q));
printf("QueueEmpty():%d\n", QueueEmpty(q));
printf("QueueLength():%d\n\n", QueueLength(q));
}
// 程序主入口
int main(int argc, char const *argv[])
{
Queue q = InitQueue();
printf("QueueMaxSize: %d\n\n", MAXSIZE);
QueueStatus(q); // 打印队满、队空、队长状态
// 入队
printf("EnQueue():");
for(int i = 1; i < MAXSIZE * 2; i+=2){
printf("%d\t", i);
EnQueue(q, i);
}
printf("\n");
QueueStatus(q);
// 出队
int val;
printf("DeQueue():");
while(!QueueEmpty(q)){
DeQueue(q, &val);
printf("%d\t", val);
}
printf("\n");
QueueStatus(q);
// 测试循环队列是否会假溢出
int num = 20;
printf("EnQueue(%d): %d\t(0 Failed, 1 Success)\n", num, EnQueue(q, num));
QueueStatus(q);
return 0;
}
结果如下:
QueueMaxSize: 10
QueueFull():0
QueueEmpty():1
QueueLength():0
EnQueue():1 3 5 7 9 11 13 15 17 19
QueueFull():1
QueueEmpty():0
QueueLength():9
DeQueue():1 3 5 7 9 11 13 15 17
QueueFull():0
QueueEmpty():1
QueueLength():0
EnQueue(20): 1(0 Failed, 1 Success)
QueueFull():0
QueueEmpty():0
QueueLength():1
源代码已上传到 GitHub Data-Structure-of-C,欢迎大家下载 C语言实现数据结构