数据结构 - 队列(链式队列、通用数据类型)

队列的概念

在该文章数据结构 - 队列(顺序队列、单一数据类型)中讲述顺序的队列,本文则浅述一下链式队列。

链式队列的思路

链式队列实现起来会灵活很多,理论上是可以做到无限长的,出队入队也比较容易实现。本文所介绍的还是一种通用数据类型式的链式队列,使用上没有之前单一数据类型的那种复杂(要先定义个队列控制结构体,定义个数组,有控制体来完成数组的控制实现队列),而是可以定义int、float等类型队列,同样自定义的结构体类型的队列也可以。具体的实现思路参考数据结构 - 队列(顺序队列、单一数据类型)

C语言代码

头文件

#ifndef __queue_H
#define __queue_H

/* 结点结构体定义 */
typedef struct _QUEUE_NODE_
{
	struct _QUEUE_NODE_ *next;
	void *data;
}QUEUE_NODE;

/* 队列结构体定义 */
typedef struct _QUEUE_
{
	QUEUE_NODE *queue_head;
	QUEUE_NODE *queue_tail;
	unsigned int count;
	unsigned char data_size;
	unsigned int queue_size;
}QUEUE;

unsigned char queue_init(QUEUE *queue, unsigned char data_size, unsigned int queue_size);
unsigned char queue_empty(QUEUE *queue);
unsigned char queue_full(QUEUE *queue);
unsigned char queue_push(QUEUE *queue, void *data);
unsigned char queue_pop(QUEUE *queue, void *data);
void queue_clean(QUEUE *queue);
void queue_free(QUEUE *queue);

#endif

在“QUEUE”结构体内部已经定义好原来控制体所需要的成员,也增加“data_size”变量实现数据类型的通用。

源文件

#include "queue.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/*********************************************************************************************************
** 函数名称:	queue_init
** 功能描述:	队列初始化
** 输 入:		queue: 队列
				data_size: 数据域大小
				queue_size: 队列长度大小 0-无限队列;其他-特定大小的循环队列
** 输 出:		1: 成功
				0: 失败
********************************************************************************************************/
unsigned char queue_init(QUEUE *queue, unsigned char data_size, unsigned int queue_size)
{
	unsigned int i = queue_size - 1; // 第一块不在循环内创建
	QUEUE_NODE *temp_node = NULL;
	QUEUE_NODE *last_node = NULL;

	if (queue_size == 0) // 无限队列
	{
		queue->queue_head = NULL;
		queue->queue_tail = NULL;
		queue->data_size = data_size;
		queue->count = 0;
		queue->queue_size = queue_size;
	}
	else // 循环队列
	{
		// 创建第一块空间作为队头
		temp_node = (QUEUE_NODE *)malloc(sizeof(QUEUE_NODE));
		if (temp_node == NULL)
		{
			return 0;
		}
		temp_node->data = malloc(queue->data_size);
		if (temp_node->data == NULL)
		{
			free(temp_node);
			return 0;
		}

		queue->queue_head = temp_node;

		while (i--) // 初始化每一块空间
		{
			// 获取前一个创建的
			last_node = temp_node;

			// 创建空间
			temp_node = (QUEUE_NODE *)malloc(sizeof(QUEUE_NODE));
			temp_node->data = malloc(queue->data_size);
			
			last_node->next = temp_node;
		}

		// 首尾相连,形成循环
		temp_node->next = queue->queue_head;

		queue->queue_tail = NULL;
		queue->data_size = data_size;
		queue->count = 0;
		queue->queue_size = queue_size;
	}

	return 1;
}

/*********************************************************************************************************
** 函数名称:	queue_empty
** 功能描述:	判断队列是否为空
** 输 入:		queue: 队列
** 输 出:		1: 为空
				0: 非空
********************************************************************************************************/
unsigned char queue_empty(QUEUE *queue)
{
	if (queue->count == 0)
	{
		return 1;
	}
	else 
	{
		return 0;
	}
}

/*********************************************************************************************************
** 函数名称:	queue_full
** 功能描述:	判断队列是否满
** 输 入:		queue: 队列
** 输 出:		1: 为满
				0: 非满
********************************************************************************************************/
unsigned char queue_full(QUEUE *queue)
{
	if (queue->queue_size != 0 && queue->count >= queue->queue_size)
	{
		return 1;
	}
	else 
	{
		return 0;
	}
}

/*********************************************************************************************************
** 函数名称:	queue_push
** 功能描述:	入队操作
** 输 入:		queue: 队列
				data: 入队变量的地址
** 输 出:		1: 入队成功  
				0: 入队失败
********************************************************************************************************/
unsigned char queue_push(QUEUE *queue, void *data)
{
	QUEUE_NODE *temp_node = NULL;

	if (queue->queue_size == 0)
	{
		// 创建空间,赋值
		temp_node = (QUEUE_NODE *)malloc(sizeof(QUEUE_NODE));
		temp_node->data = malloc(queue->data_size);
		memcpy(temp_node->data, data, queue->data_size);
		temp_node->next = NULL;

		// 更新队头队尾指针
		if (queue->count == 0)
		{
			queue->queue_head = temp_node;
		}
		else 
		{
			queue->queue_tail->next = temp_node;
		}
		queue->queue_tail = temp_node;

		// 更新计数
		queue->count++;

		return 1;
	}
	else
	{
		// 判断队列是否满了
		if (queue->count >= queue->queue_size)
		{
			return 0;
		}

		// 队尾指向空,表明刚初始化,队列为空
		if(queue->queue_tail == NULL)
		{
			queue->queue_tail = queue->queue_head;
		}
		else 
		{
			queue->queue_tail = queue->queue_tail->next;
		}

		// 赋值
		memcpy(queue->queue_tail->data, data, queue->data_size);

		// 更新计数
		queue->count++;

		return 1;
	}
}

/*********************************************************************************************************
** 函数名称:	queue_pop
** 功能描述:	出队操作
** 输 入:		queue: 队列
				data: 出队变量的地址
** 输 出:		1: 出队成功  
				0: 出队失败
********************************************************************************************************/
unsigned char queue_pop(QUEUE *queue, void *data)
{
	QUEUE_NODE *temp_node = queue->queue_head;

	// 判断队列是否为空
	if (queue->count == 0)
	{
		return 0;
	}

	if (queue->queue_size == 0)
	{
		// 更新队头
		queue->queue_head = queue->queue_head->next;

		// 获取数据
		memcpy(data, temp_node->data, queue->data_size);

		// 释放空间
		free(temp_node->data);
		free(temp_node);

		// 更新计数
		queue->count--;

		return 1;
	}
	else
	{
		// 更新队头
		queue->queue_head = queue->queue_head->next;

		// 获取数据
		memcpy(data, temp_node->data, queue->data_size);

		// 更新计数
		queue->count--;

		// 队列为空,让队尾指向空
		if (queue->count == 0)
		{
			queue->queue_tail = NULL;
		}

		return 1;
	}
}

/*********************************************************************************************************
** 函数名称:	queue_clean
** 功能描述:	队列清空
** 输 入:		queue: 队列
** 输 出:		无
********************************************************************************************************/
void queue_clean(QUEUE *queue)
{
	QUEUE_NODE *temp_node = NULL;

	if (queue->queue_size == 0)
	{
		// 循环删除
		queue->count++;
		while(--queue->count)
		{
			temp_node = queue->queue_head;
			queue->queue_head = queue->queue_head->next;

			free(temp_node->data);
			free(temp_node);
		}
		queue->queue_tail = NULL;
	}
	else 
	{
		queue->queue_tail = NULL;
		queue->count = 0;
	}
}

// 
/*********************************************************************************************************
** 函数名称:	queue_free
** 功能描述:	释放队列
** 输 入:		queue: 队列
** 输 出:		无
********************************************************************************************************/
void queue_free(QUEUE *queue)
{
	unsigned int i = 0;
	QUEUE_NODE *temp_node = NULL;

	i = queue->queue_size==0?queue->count:queue->queue_size;

	// 针对循环队列释放创建的空间
	while(i--)
	{
		temp_node = queue->queue_head;
		queue->queue_head = queue->queue_head->next;

		// 释放空间
		free(temp_node->data);
		free(temp_node);
	}

	queue->queue_head = NULL;
	queue->queue_tail = NULL;
	queue->data_size = 0;
	queue->count = 0;
	queue->queue_size = 0;
}

测试

#include <stdio.h>
#include "queue.h"

typedef struct 
{
	char name[12];
	int heght;
	float weight;
}STUDENT;

void print_student(STUDENT student)
{
	printf("name: %s, height = %d, weight = %.2f\r\n", student.name, student.heght, student.weight);
}

int main()
{
	int i = 0;
	QUEUE queue;
	QUEUE queue_stu;
	int data = 0;
	STUDENT student;
	int queue_len = 0;

	queue_init(&queue, sizeof(int), 10);
	queue_init(&queue_stu, sizeof(STUDENT), 10);

	for (i = 0; i < 11; i++)
	{
		data = i + 1;
		queue_push(&queue, &data);

		sprintf(student.name, "student%d", i);
		student.heght = 170 + i;
		student.weight = 60.5 + i;
		queue_push(&queue_stu, &student);
	}
	
	queue_len = queue.count;
	for (i = 0; i < queue_len; i++)
	{
		if (queue_pop(&queue, &data) == 1)
		{
			printf("pop<%d> = %d\r\n", i, data);
		}
	}

	queue_len = queue_stu.count;
	for (i = 0; i < queue_len; i++)
	{
		if (queue_pop(&queue_stu, &student) == 1)
		{
			print_student(student);
		}
	}

	getchar();
	return 0;
}

结果:
在这里插入图片描述

在初始化函数中,传入的变量“queue_size”还决定了队列的形式,传入0则为无限队列不限制队列长度,其他数则为特定长度的有限队列,并且在初始化时候完成空间分配。
建议: 这种链式的无限队列不建议在中断中使用,中断服务函数讲究快进快出,而链式队列每进一次队都要进行空间分配,会耗费很多的时间。
最后的最后,本人才疏学浅,此代码仅供参考交流,本人如有叙述错误,麻烦各位指正,有什么好的建议欢迎留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值