数据结构 - 队列(顺序队列、通用数据类型)

队列的概念

在文章数据结构 - 队列(顺序队列、单一数据类型)数据结构 - 队列(链式队列、通用数据类型)分别介绍了队列的不同形式,针对不同的使用场合可以选择不同形式。本文在前面的基础上,介绍一种可以通用数据结构、复用性高的顺序循环队列。

思路

在前面文章通用数据结构的队列实现原理中,使用了malloc函数动态分配数据类型大小的空间以实现可以通用数据类型,其中有限队列的形式中,是在初始化的过程中就完成了空间的分配,并链接成循环队列,但是其在链式指针上面又浪费了很多空间。而采用顺序式,也可以在初始化时候完成空间分配,并把连续的地址连成循环。
在初始化分配的时候,分配来连续的数据类型大小乘于队列长度大小的空间,并采用以下的宏定义就可以实现访问数组式的访问到队列成员。

#define ARRAY_AT(arr, size, index)	(*(((unsigned char *)arr)+(index)*(size)))

C语言代码

头文件

/*********************************************************************************************************
** Filename	:	queue.h
** Describe	:	This is a general-purpose C language queue module, with circular mode and common data structure
** Version	:	V1.1.0
** Author	:	Lamdonn
** Date		:	2022.07.22
********************************************************************************************************/
#ifndef __queue_H
#define __queue_H

typedef struct 
{
	void			*arr;			/* Address of data */
	unsigned int	item_size;		/* Size of queue item */
	unsigned int	queue_len;		/* Maximum length of queue */
	unsigned int	items_cnt;		/* Count of items */
	unsigned int	head;			/* Index of queue header */
	unsigned int	tail;			/* Index at the end of the queue */
	unsigned char	state;			/* Status of the queue */
	unsigned char	overwrite;		/* Overwrite push into queue */
}QUEUE;	

unsigned char queue_init(QUEUE *queue, unsigned int item_size, unsigned int queue_len, unsigned char overwrite);
unsigned char queue_empty(QUEUE *queue);
unsigned char queue_full(QUEUE *queue);
unsigned int queue_cnt(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结构体当中,包含了存放队列成员空间的基地址(*arr),每个成员所占用的空间大小(item_size),队列长度(queue_len),队列成员计数(items_cnt),头尾索引,覆写队列标志(overwrite,为1时,新入队的数据在满队的时候会把队首的数据覆盖掉,为0时,在满队时候新数据将不能入队)

源文件

/*********************************************************************************************************
** Filename	:	queue.c
** Describe	:	This is a general-purpose C language queue module, with circular mode and common data structure
** Version	:	V1.1.0
** Author	:	Lamdonn
** Date		:	2022.07.22
********************************************************************************************************/
#include "queue.h"
#include <string.h>
#include <stdlib.h>

#ifndef ARRAY_AT(arr, size, index)
#define ARRAY_AT(arr, size, index)	(*(((unsigned char *)arr)+(index)*(size)))
#endif

/*********************************************************************************************************
** Name		:	queue_init
** Describe	:	Initialize queue
** Input	:	*queue: Address of the queue
				item_size: Size of queue items
				queue_len: Length of queue item
				overwrite:Overwrite push into queue
** Output	:	1: Success
				0: Fail
********************************************************************************************************/
unsigned char queue_init(QUEUE *queue, unsigned int item_size, unsigned int queue_len, unsigned char overwrite)
{
	queue->arr = malloc(item_size * queue_len);		/* Allocate space to queue */
	if (queue->arr != NULL)
	{
		queue->item_size = item_size;
		queue->queue_len = queue_len;
		queue->overwrite = overwrite;
		queue->tail = 0;
		queue->head = 0;
		queue->state = 0;
		queue->items_cnt = 0;
	}
	else 
	{
		return 0;
	}

	memset(queue->arr, 0, item_size * queue_len);

	return 1;
}

/*********************************************************************************************************
** Name		:	queue_empty
** Describe	:	Judge whether the queue is empty
** Input	:	*queue: Address of the queue
** Output	:	1: Empty
				0: Not empty
********************************************************************************************************/
unsigned char queue_empty(QUEUE *queue)
{
    if (queue->state == 0)
	{
		return 1;
	}
    else
	{
		return 0;
	}
}

/*********************************************************************************************************
** Name		:	queue_full
** Describe	:	Check whether the queue is full
** Input	:	*queue: Address of the queue
** Output	:	1: Full
				0: Not full
********************************************************************************************************/
unsigned char queue_full(QUEUE *queue)
{
    if (queue->head == queue->tail && queue->state == 1)
	{
		return 1;
	}
    else
	{
		return 0;
	}
}

/*********************************************************************************************************
** Name		:	queue_cnt
** Describe	:	Get current queue count
** Input	:	*queue: Address of the queue
** Output	:	The number of current items in the queue
********************************************************************************************************/
unsigned int queue_cnt(QUEUE *queue)
{
	if (queue->state == 1)
	{
		if (queue->tail > queue->head)
		{
			return queue->tail - queue->head;
		}
		else if (queue->tail < queue->head)
		{
			return queue->tail + queue->queue_len - queue->head;
		}
		else 
		{
			return queue->queue_len;
		}
	}
    else
	{
		return 0;
	}
}

/*********************************************************************************************************
** Name		:	queue_push
** Describe	:	Queue items join the queue
** Input	:	*queue: Address of the queue
				*data: Address of queue item data
** Output	:	1: Success
				0: Fail
********************************************************************************************************/
unsigned char queue_push(QUEUE *queue, void *data)
{
	if (queue_full(queue))
	{
		if (queue->overwrite == 1)
		{
			memcpy(&ARRAY_AT(queue->arr, queue->item_size, queue->tail), data, queue->item_size);
			queue->tail++;
			queue->tail %= queue->queue_len;
			queue->head++;
			queue->head %= queue->queue_len;
			return 1;
		}
		else 
		{
			return 0;
		}
	}
	else
	{
		/* Copy this item to the queue */
		memcpy(&ARRAY_AT(queue->arr, queue->item_size, queue->tail), data, queue->item_size);
		queue->tail++;
		queue->tail %= queue->queue_len;			/* After the queue counter exceeds the maximum value, start from 0 */
		queue->state = 1;							/* Flag of non empty queue */
		queue->items_cnt++;
		return 1;
	}

	return 1;
}

/*********************************************************************************************************
** Name		:	queue_pop
** Describe	:	Queue items pop up the queue
** Input	:	*queue: Address of the queue
				*data: Address of queue item data
** Output	:	1: Success
				0: Fail
********************************************************************************************************/
unsigned char queue_pop(QUEUE *queue, void* data)
{
    if (queue_empty(queue))
    {
		return 0;
    }
    else
    {
		/* Extract data from pairs of columns */
		memcpy(data, &ARRAY_AT(queue->arr, queue->item_size, queue->head), queue->item_size); 
		queue->head++;
		queue->head %= queue->queue_len;			/* Index of loop header */
		queue->items_cnt--;
		if(queue->head == queue->tail)				/* When the number of fetches equals the number of puts, it means that the data is fetched out */
		{
			queue->state = 0;						/* Queue status changed to no data status */
		}
		return 1;
    }
}

/*********************************************************************************************************
** Name		:	queue_clean
** Describe	:	Clean queue
** Input	:	*queue: Address of the queue
** Output	:	None
********************************************************************************************************/
void queue_clean(QUEUE *queue)
{
    queue->tail = 0;
    queue->head = 0;
    queue->state = 0;
	queue->items_cnt = 0;
}

/*********************************************************************************************************
** Name		:	queue_free
** Describe	:	Release queue
** Input	:	*queue: Address of the queue
** Output	:	None
********************************************************************************************************/
void queue_free(QUEUE *queue)
{
    queue->tail = 0;
    queue->head = 0;
    queue->state = 0;
	queue->items_cnt = 0;
	queue->overwrite = 0;
	queue->queue_len = 0;
	queue->item_size = 0;
	free(queue->arr);
	queue->arr = NULL;
}

在和单一数据结构的顺序队列对比,push函数成员的赋值语句由

queue_array[queue_ctrl->tail++] = data;	

变成了

memcpy(&ARRAY_AT(queue->arr, queue->item_size, queue->tail), data, queue->item_size);
queue->tail++;

同样pop函数里面出队也发生了如此改变,原理上是没有变的。
注意:使用queue_free函数释放队列要再次初始化才可继续使用队列变量。

测试

#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, 0);
	queue_init(&queue_stu, sizeof(STUDENT), 10, 0);

	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.queue_len;
	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.queue_len;
	for (i = 0; i < queue_len; i++)
	{
		if (queue_pop(&queue_stu, &student) == 1)
		{
			print_student(student);
		}
	}

	getchar();
	return 0;
}

测试代码和前面链式通用数据类型的基本一致。
运行结果:
结果

对比

队列形式通用易用时间空间
数组型单一顺序队列一般一般
连续型通用顺序队列
无限型通用链式队列一般
有限型通用链式队列

综合对比,笔者比较推荐本文所介绍的队列形式。
最后的最后,本人才疏学浅,此代码仅供参考交流,本人如有叙述错误,麻烦各位指正,有什么好的建议欢迎留言。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值