数据结构 - 队列(顺序队列、单一数据类型)

队列的概念

队列是一种特殊的线性表,数据从队尾进从对头出,遵循“先进先出”(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;
}

运行结果:
结果
最后的最后,本人才疏学浅,此代码仅供参考交流,本人如有叙述错误,麻烦各位指正,有什么好的建议欢迎留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值