队列,在日常生活中有很多非常直观的例子。实际生活中的每次排队都是一个队列。今天我们就来看看循环队列的如何用简单的C语言来实现。本文中所有的代码均在anycodes.tk在线编程网站上测试通过。
队列进队,出对的操作实际上和前面讲过的栈差不多。只不过,栈进出在一端,而队列进出分别在队列的两端。所以一些基本的操作代码是非常容易看懂的,再次略过。本文着重分析在循环队列中如何进行错误控制,主要介绍两种方法。
1. 标志位法
这里所谓的标志位法,是指在结构体中添加一个成员变量Size,当有元素进队时,Size加一;反之,元素出对时,Size减一。因此可以通过Size和队列能容纳最多个元素Capacity比较,来确定队列满或队列空。详细见如下代码:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
struct Queue;
typedef struct Queue *pQueue;
struct Queue
{
int Capacity; //队列中可容纳最大个数的元素
int Size; //队列中已有元素的个数
int Rear; //队列中进行数据插入的一端
int Front; //队列中进行数据删除的一端
int *Array;
};
//创建队列
void createQueue(pQueue ptrQueue, int EleNum)
{
if (ptrQueue == NULL)
{
printf("Out of space!\n"); //分配空间失败
exit(1);
}
ptrQueue -> Array = malloc(sizeof(int)*(EleNum-1)); //给数组分配空间
if (ptrQueue -> Array == NULL)
{
printf("Out of space!\n"); //分配空间失败
exit(1);
}
ptrQueue -> Capacity = EleNum;
ptrQueue -> Size = 0;
ptrQueue -> Rear = 0;
ptrQueue -> Front = 0;
}
int isFull(pQueue ptrQueue)
{
return ptrQueue -> Size == ptrQueue -> Capacity -1;
}
int calRearFront(int flag, pQueue ptrQueue)
{
if(++flag == ptrQueue -> Capacity)
flag = 0;
return flag;
}
void Enqueue(pQueue ptrQueue, int ele)
{
if(isFull(ptrQueue))
{
printf("Sorry, the queue is full!\n");
exit(1);
}
ptrQueue -> Rear = calRearFront(ptrQueue->Rear, ptrQueue);
ptrQueue -> Array[ptrQueue -> Rear] = ele;
ptrQueue -> Size++;
}
int isEmpty(pQueue ptrQueue)
{
return ptrQueue -> Size == 0;
}
int Dequeue(pQueue ptrQueue)
{
int result;
if(isEmpty(ptrQueue))
{
printf("Sorry, the queue is blank!\n");
exit(1);
}
ptrQueue -> Front = calRearFront(ptrQueue -> Front, ptrQueue);
result = ptrQueue -> Array[ptrQueue -> Front];
ptrQueue -> Size++;
return result;
}
void freeStack(pQueue ptrQueue)
{
free(ptrQueue -> Array);
free(ptrQueue);
}
int main()
{
int a[3] = {12,4354,657};
int i = 0;
int topElement = 0;
int result = 0;
pQueue queue;
queue = malloc(sizeof(struct Queue));
createQueue(queue,4); //创建队列
for (; i < 3; i++)
{
Enqueue(queue, a[i]); //插入数值
}
//Enqueue(queue, 2); //队列满,报错直接退出
result = Dequeue(queue); //移除队列中的元素
printf("The dequeue element in the queue is %d!\n",result);
freeStack(queue);
return 0;
}
在anycodes.tk在线编程网站上的测试结果:
2. 使用Front和Rear联系
这里说的使用Front和Rear的联系来进行判断队空和队满是指,在循环队列中,Front = Rear时,无法判断队空还是队满,为了区别这一问题,当Front = Rear表示队空,而当(Rear+1)%N = Front时,表示队满,其中N表示队列中的空格个数。大家可以画一画图,其实这个时候在队列中有一个格子是空的。好,话不多少,直接看代码。
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
struct Queue;
typedef struct Queue *pQueue;
struct Queue
{
int Capacity; //队列中可容纳最大个数的元素
//int Size; //队列中已有元素的个数
int Rear; //队列中进行数据插入的一端
int Front; //队列中进行数据删除的一端
int *Array;
};
//创建队列
void createQueue(pQueue ptrQueue, int EleNum)
{
if (ptrQueue == NULL)
{
printf("Out of space!\n"); //分配空间失败
exit(1);
}
ptrQueue -> Array = malloc(sizeof(int)*(EleNum-1)); //给数组分配空间
if (ptrQueue -> Array == NULL)
{
printf("Out of space!\n"); //分配空间失败
exit(1);
}
ptrQueue -> Capacity = EleNum;
// ptrQueue -> Size = 0;
ptrQueue -> Rear = 0;
ptrQueue -> Front = 0;
}
int isFull(pQueue ptrQueue)
{
return (ptrQueue -> Rear + 1) % (ptrQueue -> Capacity) == ptrQueue -> Front;
}
void Enqueue(pQueue ptrQueue, int ele)
{
if(isFull(ptrQueue))
{
printf("Sorry, the queue is full!\n");
exit(1);
}
ptrQueue -> Rear++;
ptrQueue -> Array[ptrQueue -> Rear] = ele;
}
int isEmpty(pQueue ptrQueue)
{
return ptrQueue -> Rear == ptrQueue -> Front;
}
int Dequeue(pQueue ptrQueue)
{
int result;
if(isEmpty(ptrQueue))
{
printf("Sorry, the queue is blank!\n");
exit(1);
}
ptrQueue -> Front++;
result = ptrQueue -> Array[ptrQueue -> Front];
return result;
}
void freeQueue(pQueue ptrQueue)
{
free(ptrQueue -> Array);
free(ptrQueue);
}
int main()
{
int a[3] = {12,4354,657};
int i = 0;
int j = 0;
int topElement = 0;
int result = 0;
pQueue queue;
queue = malloc(sizeof(struct Queue));
createQueue(queue,4); //创建队列
for (; i < 3; i++)
{
Enqueue(queue, a[i]); //插入数值
}
//printStack(s);
// Enqueue(queue, 2); //队列满,报错直接退出
for (; j < 3; j++)
{
result = Dequeue(queue); //移除队列中的元素
printf("The dequeue element in the queue is %d!\n",result);
}
//printStack(s);
Dequeue(queue);
freeQueue(queue);
return 0;
}
在anycodes.tk上的测试结果
大家可以对照测试结果图,或者自己去测试一下,帮助自己理解。
下一篇博客将是第四章树。加油加油!