队列的实现

我们在学习数据在内存中的存储方式时就会了解到堆栈和队列,堆栈和队列是数据存储的最常见的两种,那么,我现在来介绍一下堆栈队列异同点

相同点:

栈与队列的相同点:
1.都是线性结构。
2.插入操作都是限定在表尾进行。
3.都可以通过顺序结构和链式结构实现。、
4.插入与删除的时间复杂度都是O(1),在空间复杂度上两者也一样。
5.多链栈和多链队列的管理模式可以相同。

不同点:

1、队列先进先出,栈先进后出;
2、遍历数据速度不同:
栈只能从头部取数据,也就最先放入的需要遍历整个栈最后才能取出来,而且在遍历数据的时候还得为数据开辟临时空间,保持数据在遍历前的一致性
队列则不同,它基于地址指针进行遍历,而且可以从头或尾部开始遍历,但不能同时遍历,无需开辟临时空间,因为在遍历的过程中不影像数据结构,速度要快的多
3、删除数据元素的位置不同:
栈的删除操作在表尾进行
队列的删除操作在表头进行。

相比而言,最普遍、最实用的不同点在于 数据存储时:
堆栈先入后出
队列则是先入先出

关于堆栈的知识,本人将在本人的另一篇博文——《堆栈的实现》中进行讲解。

那么,现在本人来用C语言方式实现队列的存储结构:

首先,因为我们在之后的代码中会用到boolean类型,所以,我们要编写"mec.h"头文件:

#ifndef _MEC_H_
#define _MEC_H_

typedef unsigned char boolean;

#define TRUE		1
#define FALSE		0

#define MAX_QUEUE_CAPACITY 100000                     //这个宏本来应该放在主函数或者队列的相应的.h文件中定义,但为了缩短代码量,本人就将这个宏放在mec.h头文件中

#define SET(v, i) (v |= (1 << ((i) ^ 7)))
#define CLR(v, i) (v &= ~(1 << ((i) ^ 7)))
#define	GET(v, i) (((v) & (1 << ((i) ^ 7))) != 0)

#endif

我们来构建一个结构体:

typedef struct QUEUE {
	void **data;            //这里的void **类型是为了方便各种类型的数据存储
	int capacity;           //这个成员表示数据容量,便于之后对data 的初始化
	int head;               //这个成员用于表示头节点的位置
	int tail;               //这个成员用于表示尾节点的位置
	boolean lastAction;     //这个成员用于表示上一个指令时入队列还是出队列,重要性将会在之后的代码中体现
}QUEUE;

我们要处理数据,那么第一步就是初始化数据,现在,我们来编写初始化函数
因为可能会传递错误的指针,所以可能会初始化失败,所以返回值类型为boolean类型,至于参数,当然是队列(结构体数组)的指针以及队列的数据容量,相关代码如下:

boolean initQueue(QUEUE **queueHead, const int capacity) {
	if (NULL == queueHead || NULL != *queueHead 
			|| capacity <= 0 || capacity > MAX_QUEUE_CAPACITY) {     //这里一定要注意"MAX_QUEUE_CAPACITY"是宏,需要使用者在使用时自己在头文件或者主函数中定义,本人将其定义放在了mec.h的头文件中,以便减少代码量
		return FALSE;
	}                                                                //这里是防止传递空指针,或者原来传递的指针所指向的空间已被赋过值,造成内存泄漏

	*queueHead = (QUEUE *) calloc(sizeof(QUEUE), 1);
	if (NULL == *queueHead) {
		return FALSE;
	}

	(*queueHead)->data = (void **) calloc(sizeof(void *), capacity);
	if (NULL == (*queueHead)->data) {
		free(*queueHead);
		*queueHead = NULL;
		return FALSE;
	}

	(*queueHead)->capacity = capacity;
	(*queueHead)->head = (*queueHead)->tail = 0;                    //这里是让头节点和尾节点都是第一个节点
	(*queueHead)->lastAction = OUT;

	return TRUE;
}

那么,初始化完成了,我们就要立刻联想到销毁函数

void destoryQueue(QUEUE **queueHead) {
	if (NULL == queueHead || NULL == *queueHead) {
		return;
	}

	free((*queueHead)->data);
	free(*queueHead);
	*queueHead = NULL;
}

因为我们基本操作是对于队列内数据的录入和取出,所以我们先编写判空判满函数:
判空函数

boolean isQueueEmpty(const QUEUE *queue) {
	return queue != NULL && OUT == queue->lastAction && queue->head == queue->tail;
}

判满函数

boolean isQueueFull(const QUEUE *queue) {
	return queue != NULL && IN == queue->lastAction && queue->head == queue->tail;
}

那么,接下来就是录入和取出函数了:
录入函数

boolean in(QUEUE *queue, const void *value) {
	if (NULL == queue || isQueueFull(queue)) {
		return FALSE;
	}
	queue->data[queue->tail] = value;
	queue->tail = (queue->tail + 1) % queue->capacity;
	queue->lastAction = IN;

	return TRUE;
}

取出函数

boolean out(QUEUE *queue, void **value) {
	if (NULL == queue || isQueueEmpty(queue)) {
		return FALSE;
	}
	*value = queue->data[queue->head];
	queue->head = (queue->head + 1) % queue->capacity;
	queue->lastAction = OUT;

	return TRUE;
}

这些函数就是队列实现的最基本的函数了,剩下的任何操作 几乎都是在这几个函数的基础上实现的

至于堆栈的相关讲解以及实现,请观看本人的博文——《堆栈的实现》
《堆栈的实现》

若有问题或者更好的看法,请在底下的评论区提出,本人将尽早予以讲解以及回复,谢谢!!!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值