队列的概念
队列是一种特殊的线性表,数据从队尾进从对头出,遵循“先进先出”(First In First Out)的原则。
队列的实现方式很多,以C语言为例,队列可以是顺序队列(数据存储在连续的地址空间内,队列按照队列地址顺序排列),也可以是链式队列(地址在物理空间上不连续,通过链式指针访问下一个队列成员),本文介绍的就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 <stdio.h>
#include <string.h>
/*********************************************************************************************************
** 函数名称: queue_init
** 功能描述: 队列初始化
** 输 入: queue_ctrl: 队列控制结构体变量
queue_array: 队列缓存指针
queue_len: 队列缓存长度
** 输 出: 无
********************************************************************************************************/
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
}
}
/*********************************************************************************************************
** 函数名称: queue_empty
** 功能描述: 检查队列是否为空
** 输 入: queue_ctrl: 队列控制结构体变量
** 输 出: 1: 满队
0: 非满队
********************************************************************************************************/
unsigned char queue_empty(QUEUE_CTRL *queue_ctrl)
{
if (queue_ctrl->state == 0)
{
return 1;
}
else
{
return 0;
}
}
/*********************************************************************************************************
** 函数名称: queue_full
** 功能描述: 检查队列是否满队
** 输 入: queue_ctrl: 队列控制结构体变量
** 输 出: 1: 满队
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;
}
}
/*********************************************************************************************************
** 函数名称: queue_push
** 功能描述: 入队操作
** 输 入: queue_ctrl: 队列控制结构体变量
queue_array: 队列缓存指针
data: 入队数据
** 输 出: 1: 入队成功
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; // 操作成功
}
}
/*********************************************************************************************************
** 函数名称: queue_pop
** 功能描述: 出队操作
** 输 入: queue_ctrl: 队列控制结构体变量
queue_array: 队列缓存指针
data: 用于接收出队数据的指针
** 输 出: 1: 出队成功
0: 出队失败
********************************************************************************************************/
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; // 队列读取操作成功
}
}
/*********************************************************************************************************
** 函数名称: queue_clean
** 功能描述: 队列清空
** 输 入: queue_ctrl: 队列控制结构体变量
queue_array: 队列缓存指针
** 输 出: 无
********************************************************************************************************/
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 <stdio.h>
#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> = %d\r\n", i, data);
}
}
getchar();
return 0;
}
运行结果:
最后的最后,本人才疏学浅,此代码仅供参考交流,本人如有叙述错误,麻烦各位指正,有什么好的建议欢迎留言。