循环队列的定义及特点
循环队列是一种基于数组实现的队列数据结构,其特点是队尾指针可以循环回到数组的起始位置。
循环队列的定义包括以下几个关键属性:
1. 队列的容量:即数组的长度,表示队列可以存储的元素个数。
2. 队头指针(front):指向队列中第一个元素的位置。
3. 队尾指针(rear):指向队列中最后一个元素的下一个位置。
循环队列的特点包括:
1. 利用数组实现:循环队列使用数组作为底层数据结构,可以通过索引直接访问元素,具有高效的随机访问性能。
2. 循环利用空间:当队尾指针到达数组末尾时,如果队头指针仍然指向数组的起始位置,说明队列已满,此时可以将队尾指针循环回到数组的起始位置,实现空间的循环利用。
3. 避免元素搬移:在普通队列中,当队列头部有元素出队后,为了保持队列的连续性,需要将后续元素向前搬移。而在循环队列中,由于队尾指针可以循环回到数组起始位置,可以直接将新元素插入到队尾,无需搬移元素,提高了入队操作的效率。
4. 判空和判满条件:循环队列的判空条件是队头指针等于队尾指针,判满条件是队尾指针的下一个位置等于队头指针。这样可以避免队列为空时无法区分是队列满还是空的问题。
循环队列的操作
- 初始化
- 入队
- 出队
- 判空
- 判满
- 获取队列大小
- 输出队列
代码实现
初始化
/*循环队列初始化*/
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 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;
}
判满
/*队满*/
int isfull(CirclesQueue* Q)
{
return (Q->rear + 1) % MAXSIZE == Q->front ? 1 : 0;
}
队列元素个数
/*计算队列中的元素个数*/
int size(CirclesQueue* Q) {
return (Q->rear - Q->front + MAXSIZE) % MAXSIZE;
}
/*获取队列的首元素*/
int frontElement(CirclesQueue* Q, DataType* x) {
if (isempty(Q)) {
printf("队列为空!100002\n");
return 100002;
}
*x = Q->data[(Q->front + 1) % MAXSIZE];
return 0;
}
队列首元素
/*获取队列的首元素*/
int frontElement(CirclesQueue* Q, DataType* x) {
if (isempty(Q)) {
printf("队列为空!100002\n");
return 100002;
}
*x = Q->data[(Q->front + 1) % MAXSIZE];
return 0;
}
输出队列元素
/*输出队列中的所有元素*/
void printfQueue(CirclesQueue* Q) {
int i = (Q->front + 1) % MAXSIZE;
printf("队列元素:");
while (i != (Q->rear + 1) % MAXSIZE) {
printf("%d ", Q->data[i]);
i = (i + 1) % MAXSIZE;
}
printf("\n\n");
}
运行结果
完整demo
main.c
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "CirclesQueue.h"
int main(int argc, char* argv[])
{
CirclesQueue Q;
DataType x;
int cmd;
char yn;
printf("-----------循环队列演示-----------\n");
do
{
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(" 0. 退出\n");
printf(" 请选择(0~8):");
scanf("%d", &cmd);
switch (cmd)
{
case 1:
init(&Q);
printf("队列已初始化!\n\n");
break;
case 2:
printf("请输入要入队的元素x=");
scanf("%d", &x);
if (!enqueue(&Q, x))
{
printf("元素x=%d已入队\n\n", x);
}
break;
case 3:
getchar();
printf("确定要出队(出队会将删除对首元素, y or n)?");
scanf("%c", &yn);
if (yn == 'y' || yn == 'Y')
{
if (!dequeue(&Q, &x))
{
printf("队首元素【%d】已出队!\n\n", x);
}
}
break;
case 4:
if (isempty(&Q)) {
printf("队列为空!\n\n");
}
else {
printf("队列不为空!\n\n");
}
break;
case 5:
if (isfull(&Q)) {
printf("队列已满!\n\n");
}
else {
printf("队列未满!\n\n");
}
break;
case 6:
printf("队列中的元素个数:%d\n\n", size(&Q));
break;
case 7:
if (frontElement(&Q, &x) == 0) {
printf("队首元素:%d\n\n", x);
}
break;
case 8:
printfQueue(&Q);
break;
}
} while (cmd != 0);
return 0;
}
CirclesQueue.h
#pragma once
/*
CirclesQueue.h
循环队列
*/
#define MAXSIZE 100
typedef int DataType;
typedef struct
{
DataType data[MAXSIZE];
int front;
int rear;
}CirclesQueue;
/*循环队列初始化*/
int init(CirclesQueue* Q);
/*入队*/
int enqueue(CirclesQueue* Q, DataType x);
/*队满?*/
int isfull(CirclesQueue* Q);
/*出队*/
int dequeue(CirclesQueue* Q, DataType*);
/*队空*/
int isempty(CirclesQueue* Q);
/*计算队列中的元素个数*/
int size(CirclesQueue* Q);
/*获取队列的首元素*/
int frontElement(CirclesQueue* Q, DataType* x);
/*输出队列中的所有元素*/
void printfQueue(CirclesQueue* Q);
CirclesQueue.c
/*
CirclesQueue.c
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#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 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;
}
/*队满*/
int isfull(CirclesQueue* Q)
{
return (Q->rear + 1) % MAXSIZE == Q->front ? 1 : 0;
}
/*计算队列中的元素个数*/
int size(CirclesQueue* Q) {
return (Q->rear - Q->front + MAXSIZE) % MAXSIZE;
}
/*获取队列的首元素*/
int frontElement(CirclesQueue* Q, DataType* x) {
if (isempty(Q)) {
printf("队列为空!100002\n");
return 100002;
}
*x = Q->data[(Q->front + 1) % MAXSIZE];
return 0;
}
/*输出队列中的所有元素*/
void printfQueue(CirclesQueue* Q) {
int i = (Q->front + 1) % MAXSIZE;
printf("队列元素:");
while (i != (Q->rear + 1) % MAXSIZE) {
printf("%d ", Q->data[i]);
i = (i + 1) % MAXSIZE;
}
printf("\n\n");
}
小结
1. 循环队列的定义:循环队列是一种基于数组实现的队列数据结构,其特点是队尾指针可以循环回到数组的起始位置。
2. 循环队列的实现:循环队列的实现需要定义队列的容量、队头指针和队尾指针等关键属性,并且需要考虑循环利用空间和避免元素搬移等问题。
3. 循环队列的操作:循环队列支持入队、出队、判空、判满等基本操作。入队操作需要将新元素插入到队尾,并且需要考虑队列已满的情况;出队操作需要将队头元素弹出,并且需要考虑队列为空的情况。
参考资料
百度