队列是一种特殊的线性表,数据从队尾进从对头出,遵循“先进先出”(First In First Out)的原则。
队列的实现方式很多,以C语言为例,队列可以是顺序队列(数据存储在连续的地址空间内,队列按照队列地址顺序排列),也可以是链式队列(地址在物理空间上不连续,通过链式指针访问下一个队列成员),本文介绍的就C语言实现的顺序队列。
顺序队列通常采用数组的形式,在队列成员排在数组当中,有新的数据进来就排在数组后面,数据出去就从数组前面出去。但其中就会有个问题,如果要保证数组的第一位总是队头,那么出去一个数据就要把剩下的全部数据都要向前挪动一位,这将会带来很大的计算量,显然不是理想的做法。
这时候循环队列的思路就出来,可以假想这个数组是个循环的,首尾相接的,就不要一定要保证队头总是在数组的第一个位置,只需要增加个索引记住队头的位置,在出队的时候找到索引位置的数据,让其数据出队就行,然后更新索引到队列的下一个位置作为队头。同样增加个队尾索引,以方便入队。
在编程时候,就可以定义个队列控制体的结构体来记录队列的情况,定义个数组来存储队列。
#ifndef __queue_H
#define __queue_H
typedef int QUEUE_TYPE;
// 队列控制结构体。在队列应用中,定义一个QUEUE_CTRL Q,再定义一个队列BUF,同时对要对BUF及Q初始化
typedef struct
{
unsigned int head; // 队头
unsigned int tail; // 队尾
unsigned int size; // 队列大小
unsigned char state; // 队列状态 1:队列中有数据 0:队列中无数据
}QUEUE_CTRL; // 队列控制结构体
void queue_init(QUEUE_CTRL *queue_ctrl, QUEUE_TYPE *queue_array, unsigned int queue_len);
unsigned char queue_empty(QUEUE_CTRL *queue_ctrl);
unsigned char queue_full(QUEUE_CTRL *queue_ctrl);
unsigned char queue_push(QUEUE_CTRL *queue_ctrl, QUEUE_TYPE *queue_array, QUEUE_TYPE data);
unsigned char queue_pop(QUEUE_CTRL *queue_ctrl, QUEUE_TYPE *queue_array, QUEUE_TYPE *data);
void queue_clean(QUEUE_CTRL *queue_ctrl, QUEUE_TYPE *queue_array);
#endif
可以看到,在队列控制结构体当中,定义了队头队尾的索引,以及队列的大小和队列状态。操作函数就包含有初始化、入队、出队、清空、检查是否满是否空。
源文件#include "queue.h" #include#include void queue_init(QUEUE_CTRL *queue_ctrl, QUEUE_TYPE *queue_array, unsigned int queue_len) { unsigned int i = 0; queue_ctrl->tail = 0; queue_ctrl->head = 0; queue_ctrl->size = queue_len; queue_ctrl->state = 0; for (i = 0; i < queue_ctrl->size; i++) { queue_array[i] = 0;//初始化数据为0 } } unsigned char queue_empty(QUEUE_CTRL *queue_ctrl) { if (queue_ctrl->state == 0) { return 1; } else { return 0; } } unsigned char queue_full(QUEUE_CTRL *queue_ctrl) { if (queue_ctrl->head == queue_ctrl->tail && queue_ctrl->state == 1) { return 1; } else { return 0; } } unsigned char queue_push(QUEUE_CTRL *queue_ctrl, QUEUE_TYPE *queue_array, QUEUE_TYPE data) { if (queue_full(queue_ctrl)) // 队列满了 { return 0; // 操作失败 } else // 队列未满 { queue_array[queue_ctrl->tail++] = data; // 入队 queue_ctrl->tail %= queue_ctrl->size; // 入队计数器超最大值后,从0开始 queue_ctrl->state = 1; // 队列非空标志 return 1; // 操作成功 } } unsigned char queue_pop(QUEUE_CTRL *queue_ctrl, QUEUE_TYPE *queue_array, QUEUE_TYPE *data) { if(queue_empty(queue_ctrl)) // 队列无数据 { return 0; // 队列读取失败 } else { *data = queue_array[queue_ctrl->head++]; // 读数据 queue_ctrl->head %= queue_ctrl->size; // 循环 if(queue_ctrl->head == queue_ctrl->tail) // 当取出数==放入数时,说明数据取出完了 { queue_ctrl->state = 0; // 队列状态改为无数据状态 } return 1; // 队列读取操作成功 } } void queue_clean(QUEUE_CTRL *queue_ctrl, QUEUE_TYPE *queue_array) { unsigned int i = 0; queue_ctrl->tail = 0; queue_ctrl->head = 0; queue_ctrl->state = 0; #if 1 // 可有可无 for(i = 0; i < queue_ctrl->size; i++) { queue_array[i] = 0; } #endif }
在代码中看到,真正实现了循环队列将数组首尾相连的是求余操作。
queue_ctrl->head %= queue_ctrl->size;
求余就让索引超过数组大小后回到第一个位置。
#include#include "queue.h" #define QUEUE_LEN (10) typedef struct { QUEUE_CTRL ctrl; QUEUE_TYPE buf[QUEUE_LEN]; }QUEUE; int main() { int i = 0; QUEUE queue; QUEUE_TYPE data = 0; queue_init(&queue.ctrl, queue.buf, QUEUE_LEN); for (i = 0; i < 11; i++) { data = i + 1; queue_push(&queue.ctrl, queue.buf, data); } for (i = 0; i < queue.ctrl.size; i++) { if (queue_pop(&queue.ctrl, queue.buf, &data) == 1) { printf("pop<%d> = %drn", i, data); } } getchar(); return 0; }
运行结果:
最后的最后,本人才疏学浅,此代码仅供参考交流,本人如有叙述错误,麻烦各位指正,有什么好的建议欢迎留言。



