概念
关于队列的相关内容,在之前的文章已经详细介绍过了,请参见《也没想象中那么神秘的数据结构-先来后到的“队列”(顺序队列)》,本文主要将循环队列相关内容。
循环队列:在顺序队列中存在一种假溢出的现象,为了解决这种现象,将队列头尾相接,当后面的满了就从头开始,这种头尾相接的顺序存储结构我们称之为循环队列。
核心
队列的结构:队列包含front指向队头、rear指向队尾和size记录队列元素个数。
队列空的时候,front=rear,此时size=0。
队列满的时候,此时front和rear相隔一个,size=MAX_SIZE(最大长度)-1。之所以队列元素个数比最大个数少一个,是为了防止front和rear重合。
![]()
入队:rear向后移一位,此时需要判断,若超出了最大长度,需要从0开始,可以使用rear=rear+1%MAX_SIZE。
![]()
出队:front向后移一位,此时需要判断,若超出了最大长度,需要从0开始,可以使用front=front+1%MAX_SIZE。
示例
★包含头文件queue_circular.h和源文件queue_circular.c(均已验证通过)。
queue_circular.h
/** * @Filename : queue_circular.h * @Revision : $Revision: 1.0 $ * @Author : Feng(微信公众号:不只会拍照的程序猿) * @Description : 循环队列示例 **/ #ifndef __QUEUE_CIRCULAR_H__ #define __QUEUE_CIRCULAR_H__ #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 10 /* 循环队列结构定义 */ struct t_queue{ int buff[MAX_SIZE]; /* 保存队列元素 */ int front; /* 指向队头 */ int rear; /* 指向队尾 */ int size; /* 队列元素个数 */ }; /** * @初始化队列 * @p_queue:队列 **/ void queue_init(struct t_queue *p_queue); /** * @删除队列 * @p_queue:队列 **/ void queue_deinit(struct t_queue *p_queue); /** * @判断队列是否已满 * @p_queue:队列 * @返回1表示已满,0表示未满 **/ int queue_is_full(const struct t_queue *p_queue); /** * @判断队列是否已空 * @p_queue:队列 * @返回1表示已空,0表示未空 **/ int queue_is_empty(const struct t_queue *p_queue); /** * @获取队列元素个数 * @p_queue:队列 * @返回元素个数 **/ int queue_get_size(const struct t_queue *p_queue); /** * @入队操作 * @p_queue:队列 data:队列元素 * @返回1表示成功,0表示失败 **/ int queue_push(struct t_queue *p_queue, int data); /** * @出队操作 * @p_queue:队列 data:队列元素 * @返回1表示成功,0表示失败 **/ int queue_pop(struct t_queue *p_queue, int *p_data); /** * @获取队头 * @p_queue:队列 p_data:保存队头元素 * @返回1表示成功,0表示失败 **/ int queue_get_front(const struct t_queue *p_queue, int *p_data); /** * @打印队列元素 * @p_queue:队列 **/ void queue_print(const struct t_queue *p_queue); #endif
queue_circular.c
/** * @Filename : queue_circular.c * @Revision : $Revision: 1.0 $ * @Author : Feng(微信公众号:不只会拍照的程序猿) * @Description : 循环队列示例 **/ #include "queue_circular.h" /** * @初始化队列 * @p_queue:队列 **/ void queue_init(struct t_queue *p_queue) { p_queue->front = 0; p_queue->rear = 0; p_queue->size = 0; } /** * @删除队列 * @p_queue:队列 **/ void queue_deinit(struct t_queue *p_queue) { p_queue->front = 0; p_queue->rear = 0; p_queue->size = 0; } /** * @判断队列是否已满 * @p_queue:队列 * @返回1表示已满,0表示未满 **/ int queue_is_full(const struct t_queue *p_queue) { return (p_queue->size >= MAX_SIZE - 1); } /** * @判断队列是否已空 * @p_queue:队列 * @返回1表示已空,0表示未空 **/ int queue_is_empty(const struct t_queue *p_queue) { return (p_queue->size == 0); } /** * @获取队列元素个数 * @p_queue:队列 * @返回元素个数 **/ int queue_get_size(const struct t_queue *p_queue) { return (p_queue->size); } /** * @入队操作 * @p_queue:队列 data:队列元素 * @返回1表示成功,0表示失败 **/ int queue_push(struct t_queue *p_queue, int data) { // the queue is full, push failed if (queue_is_full(p_queue)) return 0; p_queue->buff[p_queue->rear++] = data; p_queue->rear %= MAX_SIZE; p_queue->size++; return 1; } /** * @出队操作 * @p_queue:队列 data:队列元素 * @返回1表示成功,0表示失败 **/ int queue_pop(struct t_queue *p_queue, int *p_data) { // the queue is empty, pop failed if (queue_is_empty(p_queue)) return 0; *p_data = p_queue->buff[p_queue->front++]; p_queue->front %= MAX_SIZE; p_queue->size--; return 1; } /** * @获取队头 * @p_queue:队列 p_data:保存队头元素 * @返回1表示成功,0表示失败 **/ int queue_get_front(const struct t_queue *p_queue, int *p_data) { if (queue_is_empty(p_queue)) return 0; *p_data = p_queue->buff[p_queue->front]; return 1; } /** * @打印队列元素 * @p_queue:队列 **/ void queue_print(const struct t_queue *p_queue) { int i; for (i=0; i<p_queue->size; i++) printf("%d ", p_queue->buff[(i+p_queue->front)%MAX_SIZE]); printf("\n"); } /** * @顺序队列测试代码 **/ int main(void) { int data; struct t_queue my_queue; queue_init(&my_queue); /* 初始化队列,此时为空队列 */ printf("the queue is %s\n", queue_is_empty(&my_queue) ? "empty" : "not empty"); printf("---------------------------------------\n"); /* 入队,队列:25 41 16 7 8 19 22,元素个数为7 */ queue_push(&my_queue, 25); queue_push(&my_queue, 41); queue_push(&my_queue, 16); queue_push(&my_queue, 7); queue_push(&my_queue, 8); queue_push(&my_queue, 19); queue_push(&my_queue, 22); printf("the size of queue is: %d\n", queue_get_size(&my_queue)); queue_print(&my_queue); printf("---------------------------------------\n"); /* 入队35 38 [11 22](队列已满,入队失败),队列:25 41 16 7 8 19 22 35 38,个数9 */ queue_push(&my_queue, 35); queue_push(&my_queue, 38); queue_push(&my_queue, 11); queue_push(&my_queue, 22); printf("the size of queue is: %d\n", queue_get_size(&my_queue)); queue_print(&my_queue); printf("the queue is %s\n", queue_is_full(&my_queue) ? "full" : "not full"); printf("---------------------------------------\n"); /* 队头元素为25,第一次出队25,第二次出队41,队列:16 7 8 19 22 35 38,个数7 */ if (queue_get_front(&my_queue, &data)) printf("the front queue data is: %d\n", data); if (queue_pop(&my_queue, &data)) printf("the pop queue data is: %d\n", data); if (queue_pop(&my_queue, &data)) printf("the pop queue data is: %d\n", data); printf("the size of queue is: %d\n", queue_get_size(&my_queue)); queue_print(&my_queue); printf("---------------------------------------\n"); /* 清除队列,个数0 */ queue_deinit(&my_queue); printf("the size of queue is: %d\n", queue_get_size(&my_queue)); return 0; }
结论
feng:queue$ gcc -o queue_circular queue_circular.c feng:queue$ ./queue_circular the queue is empty --------------------------------------- the size of queue is: 7 25 41 16 7 8 19 22 --------------------------------------- the size of queue is: 9 25 41 16 7 8 19 22 35 38 the queue is full --------------------------------------- the front queue data is: 25 the pop queue data is: 25 the pop queue data is: 41 the size of queue is: 7 16 7 8 19 22 35 38 --------------------------------------- the size of queue is: 0 feng:queue$
本示例仅为循环队列示例,公众号也提供顺序栈示例《也没想象中那么神秘的数据结构-先来后到的“队列”(顺序队列)》、《也没想象中那么神秘的数据结构-先来后到的“队列”(链式队列)》以及队列的典型应用示例。
往期 · 推荐
也没想象中那么神秘的数据结构-先来后到的“队列”(链式队列)
关注
更多精彩内容,请关注微信公众号:不只会拍照的程序猿,本人致力分享linux、设计模式、C语言、嵌入式、编程相关知识,也会抽空分享些摄影相关内容,同样也分享大量摄影、编程相关视频和源码,另外你若想要本文章源码请关注公众号:不只会拍照的程序猿,后台回复:数据结构源码,也可点击此处下载。