数据结构---栈和队列详解(下)

引言:

大家在使用电脑时有没有经历过,机器有时会处于疑似死机状态,鼠标点什么似乎都没用,双击任何快捷方式都不动弹。就当你失去耐心,打算reset时突然它就像醒酒了一样,把你刚才单击的所有操作都按顺序执行了一遍。这是因为操作系统在当时可能cpu一时忙不过来,等前面的事情忙完后,后面多个指令需要通过一个通道输出,按先后次序排队执行造成的结果。再比如,像移动、联通、电信等电话客服,客服人员和客户相比总是少数的,在所有客服人员都占线的情况下,客户会被要求等待,直到某个客服人员空下来,才能让最先开始等待的客户接通电话,这里也是将当前所有拨打客服电话的客户进行了排队处理。

操作系统和客服系统中,都是应用了一种数据结构,来实现方才提到的先进先出的排队功能,这就是队列。

一、队列的定义

1、队列是一种先进先出(First in first out)的线性表,简称:FIFO;允许插入的一端称为队尾,允许删除的一端叫做队头。

2、队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。

二、队列的实现思路

首先我们用链表来实现队列,队列的结构是由一个个的节点组成的,定义俩个指针,一个指向队头,一个指向队尾。节点也需要定义结构体。

三、代码具体实现

1、定义队列结构

cpp 复制代码
//1、先定义队列结点的结构
typedef int QDataType;
typedef struct QueueNode 
{
	QDataType data;
	QueueNode* next;
}QueueNode;
//2、定义队列的结构
typedef struct Queue
{
	QueueNode* phead;//队列头的
	QueueNode* ptail;//队列的尾
}Queue;

2、队列结构初始化

cpp 复制代码
//初始化
void QueueInit(Queue* pq)
{
	assert(pq);
		return pq->phead =pq->ptail= NULL;
}

3、判空

cpp 复制代码
//队列判空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead ==NULL;
}

4、出队

cpp 复制代码
//出队--队头
void QueuePop(Queue* pq)
{
	assert(!QueueEmpty(pq));
	if (pq->phead == pq->ptail)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
	{
		QueueNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;

	}
}

5、队列有效元素

cpp 复制代码
//队列有效元素
int QueueSize(Queue* pq)
{

	assert(pq);
	QueueNode* pcur = pq->phead;
	int size = 0;
	while (pcur)

	{
		size++;
		pcur = pcur->next;
	}
	return size;
}

6、取队头元素

cpp 复制代码
//取队头元素(数据)
QDataType QueueFront(Queue* pq)
{
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}

7、取队尾元素

cpp 复制代码
//取队尾数据
QDataType QueueBack(Queue* pq)
{
	assert(!QueueEmpty(pq));
	return pq->ptail->data;
}

8、队列的销毁

cpp 复制代码
//销毁队列
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		QueueNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->ptail = NULL;
}

9、入队

cpp 复制代码
//入队--队尾
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;
	if (pq->phead == NULL)
	{
		pq->phead = pq->ptail = newnode;

	}
	else
	{
		//队列非空
		pq->ptail->next = newnode;
		pq->ptail = pq->ptail->next;
	}
}
四、总结

1、栈是限定仅在表尾插入和删除操作的线性表,队列是只允许在一端进行插入操作,另一端进行删除操作的线性表。

2、它们都可以用线性表的顺序存储结构来实现,但都存在着顺序存储的一些弊端,因此它们各自有各自的技巧来解决这个问题。

对于栈来说,如果是俩个相同数据类型的栈,则可以用数组的俩端做栈底的方法来让俩个栈共享数据,这就可以最大化利用数组的空间。

对于队列来说,为了避免数组在插入和删除是需要移动数据,于是就引入了循环队列,使得队头和队尾可以在数组中循环变化。解决了移动数据的时间损耗,使得本来插入和删除是O(n)的时间复杂度变成了O(1)。

它们也都可通过链式存储结构来实现,实现原则上与线性表基本相同,如下图所示:

|--------|---|
| 顺序栈 | |
| 俩栈共享空间 | |
| 链栈 | |
[栈]

|------|---|
| 顺序队列 | |
| 循环队列 | |
| 链队列 | |
[队列]

五、结尾语

人生就像一个很大的栈演变。人生又仿佛是一天一天小小的栈重现。童年时,父母每天抱你不断地进出家门,壮年你每天奔波于事业与家之间,老年你每天独自蹒跚于养老院的门里屋前。

人生,更需要又进栈出栈精神的体现。在哪里跌倒就应该在哪里爬起来。无论陷入何等困境,只要抬头能仰望蓝天,就有希望,不断进取,你就可以让出头之日重现。困难不会永远存在,强者才能勇往直前。

人生有是一个又一个小小的队列重现,春夏秋冬轮回年年,早中晚夜循环天天。变化的是时间,不变的是你对未来执着的信念。

人生,更需要有队列精神的体现。南极到北极,不过是南纬90°到北纬90°的队列,如果你中途犹豫,临时转向,也许你就只能和企鹅相伴永远。可事实上,无论那个方向,只要你坚持到底,你都可以到达终点。

相关推荐
jinmo_C++6 小时前
数据结构_哈夫曼编码(Huffman)完整指南:从原理到实现,附考研真题详解
数据结构·考研
那我掉的头发算什么6 小时前
【数据结构】优先级队列(堆)
java·开发语言·数据结构·链表·idea
如竟没有火炬7 小时前
LRU缓存——双向链表+哈希表
数据结构·python·算法·leetcode·链表·缓存
爱吃生蚝的于勒7 小时前
【Linux】零基础学会Linux之权限
linux·运维·服务器·数据结构·git·算法·github
爱编程的化学家8 小时前
代码随想录算法训练营第27天 -- 动态规划1 || 509.斐波那契数列 / 70.爬楼梯 / 746.使用最小花费爬楼梯
数据结构·c++·算法·leetcode·动态规划·代码随想录
一只鱼^_12 小时前
力扣第470场周赛
数据结构·c++·算法·leetcode·深度优先·动态规划·启发式算法
Univin19 小时前
C++(10.4)
开发语言·数据结构·c++
Jayden_Ruan1 天前
C++十进制转二进制
数据结构·c++·算法