《栈和队列》的模拟实现(顺序栈) (链队列)

目录

前言:

栈和队列:

栈:

队列:

模拟实现《栈》:

1.typedef数据类型

2.初始化栈 

3.销毁栈

4.入栈

5.出栈

6.取栈顶元素

7.判断栈是否为空

8.栈的大小

9.打印栈

模拟实现《队列》 :

1.typedef数据类型

2.初始化队列

3.销毁队列

 4.入队列

5.出队列

6.取队头

7.取队尾

8.判断队列是否为空

9.队列的元素个数

 10.打印队列

总结:


 

前言:

我们在上几篇的blog中,对于顺序表和两种链表都进行了模拟实现,已经相关的Leecode的oj题目我们都已经见识过了,下面我们就来对我们所学习的顺序表和链表进行提高练习,那就不得动手来实现实现《栈和队列》了。

栈和队列:

栈:

栈(Stack)是一种数据结构,可以理解为“一摞书”,它的特点是只能在一端进行操作,也就是称为栈顶(top),另一端称为栈底(bottom)。栈的基本操作有两个:push(入栈)和pop(出栈)。push操作往栈顶添加元素,pop操作从栈顶删除元素。

栈的特点是先进后出(Last In First Out,LIFO),即后

加入的元素先被取出。这种特性使得栈常常被用来处理一些具有“后效性”的问题,比如递归的函数调用、表达式求值、括号匹配、浏览器的“前进”和“后退”功能等等。

示意图:

  +---+         <- 栈顶
  | 3 |
  +---+
  | 2 |
  +---+
  | 1 |
  +---+         <- 栈底

队列:

队列是一种具有特定操作的数据结构,遵循“先进先出”(First In, First Out,FIFO)的原则。

示意图:

  Front                          Rear
    |                             |
  +---+  +---+  +---+  +---+  +---+
  | 1 |  | 2 |  | 3 |  | 4 |  | 5 |
  +---+  +---+  +---+  +---+  +---+
 

在这个示意图中,队列的前端(Front)指向队列的第一个元素,队列的后端(Rear)指向队列的最后一个元素。元素1最先进队列,然后是2、3、4、5。如果要出队列,将首先出队列的是元素1,然后是2、3、4、5。

队列的基本操作包括:

  • enqueue:将元素加入队列的末尾。
  • dequeue:从队列的前端移除元素。
  • front:获取队列的前端元素,但不移除。
  • isEmpty:检查队列是否为空。

队列通常用于模拟实际情况,例如任务调度、广度优先搜索等场景。在编程中,队列是一种常见的数据结构。

模拟实现《栈》:

1.typedef数据类型

typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

由于这部分与咱们上次将的顺序表的实现,也就是通讯录大为相似,所以在这里我也不过多赘述,有需要的同学可以访问顺序表的blog:

《动态顺序表》的实现-CSDN博客

2.初始化栈 

void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	pst->capacity = 0;
	pst->top = -1;
}

 这里要注意的是,在之前的顺序表中我们是定义了size来表示数组的长度,但是在这里,我们是利用top来定义的栈顶元素,并将其初始化为-1。

其实初始化为0还是初始化为-1都可以,没有过多的讲究,如果初始化为0的话,我们在后续判断栈是否为空理解起来就显得十分麻烦。

如果是定义top = -1,就显得尤为轻松。

在此我们统一定义top = -1.

3.销毁栈

void STDestory(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = -1;
	pst->capacity = 0;
}

4.入栈

void STPush(ST* pst, STDataType x)
{
	assert(pst);
	int newcapacity = (pst->capacity == 0) ? 4 : 2 * (pst->capacity);
	STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);
	if (tmp == NULL)
	{
		perror("STPush -> realloc");
		exit(-1);
	}
	pst->a = tmp;
	pst->capacity = newcapacity;
	pst->top++;
	pst->a[pst->top] = x;

}

我们在此作出了与顺序表和通讯录不一样的地方,就是我们在此并没有再创建一个函数用来实现判断扩容,因为我们全部函数中有且只有入栈函数要进行判断是否需要扩容的操作。

因此我们直接在函数内部实现即可。

5.出栈

void STPop(ST* pst)
{
	assert(pst);
	if (pst->top != -1)
	{
		pst->top--;
	}
}

6.取栈顶元素

STDataType STTop(ST* pst)
{
	assert(pst);
	if (pst->top != -1)
	{
		return pst->a[pst->top];
	}
	return -1;
}

7.判断栈是否为空

bool STEmpty(ST* pst)
{
	assert(pst);
	if (pst->top == -1)
	{
		return true;
	}
	return false;
}

8.栈的大小

int STSize(ST* pst)
{
	assert(pst);
	return pst->top + 1;
}

9.打印栈

void STPrint(ST* pst)
{
	assert(pst);
	for (int i = 0; i <= pst->top; i++)
	{
		printf("%d  ", pst->a[i]);
	}
}

以上就是栈的全部模拟实现,因为我们用的是顺序表来模拟实现栈,所以大部分内容参考之前blog即可,接下来我们一起实现队列。


 

模拟实现《队列》 :

1.typedef数据类型

typedef int QDataType;

typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int sz;
}Queue;

我们在本文实现的是链队列,但是不同于我们之前对单链表的实现,由于我们在此需要经常进行找尾操作,而且尾指针时不时会发生改变,因此我们可以再创建一个结构体,里面包含了我们所需要的两个指针,一个头指针和一个尾指针,这样我们在调试的时候也不必需要传二级指针了。

如图:

 可能现在还不是很理解,接下来我们动手实现几个函数,就能迎刃而解了。

2.初始化队列

void QueueInit(Queue* pq)
{
	pq->sz = 0;
	pq->phead = pq->ptail = NULL;
}

3.销毁队列

void QueueDestroy(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	QNode* cur = NULL;
	while (cur)
	{
		cur = pq->phead->next;
		free(pq->phead);
		pq->phead = cur;
	}
	pq->ptail = pq->phead = NULL;
}

 4.入队列

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("QueuePush -> malloc");
		exit(-1);
	}
	newnode->val = x;
	newnode->next = NULL;

	if (pq->phead == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->sz++;

}

因为是链表,所以我们入队列的时候要动态开辟出一个新的节点来存放数据而此时链表是空的,而队列本质是尾插,头删,所以我们才采用的链表。如图:

继续入队时,注意仔细观察*phead和*ptail的变化。

 

后面当我想要加入数据的时候就以此类推。

5.出队列

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	if (pq->ptail == pq->phead)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
	{
		QNode* cur = pq->phead->next;
		free(pq->phead);
		pq->phead = cur;
		pq->sz--;
	}
}

由于队列是“先进先出”实际上是链表的头删操作。

这里要注意的是,存在两种情况

1.队列仅有一个节点

2.队列多个节点

当队列仅有一个节点时,随着对pq->phead释放,不仅要将pq->phead置为NULL,

同时也要对pq->ptail进行操作!!!

6.取队头

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->phead->val;
}

7.取队尾

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->ptail->val;
}

8.判断队列是否为空

bool QueueEmpty(Queue* pq)
{
	if (pq->phead != NULL)
	{
		return false;
	}
	return true;
}

9.队列的元素个数

int QueueSize(Queue* pq)
{
	return pq->sz;
}

 10.打印队列

void QueuePrint(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->phead;
	while (cur)
	{
		printf("%d->", cur->val);
		cur = cur->next;
	}
	printf("NULL\n");
}

总结:

以上就是栈和队列的模拟实现。

《栈》的源代码:Data structures amd algorithms: 关于数据结构和算法的代码 - Gitee.com

《队列》的源代码:Data structures amd algorithms: 关于数据结构和算法的代码 - Gitee.com 

记住

“坐而言不如起而行”

Action speak louder than words! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/172127.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue3中使用全局自定义指令和组件自定义指令

这篇文章会教大家如何实现全局自定义指令和组件自定义指令 &#x1f4d3;全局自定义指令和组件自定义指令的区别&#xff0c;除了写法不同和作用不同&#xff0c;其他的包括生命周期的使用方法都是一致的&#xff0c;全局自定义指令在main.ts中注册后整个项目都可以使用&#x…

每日一题(LeetCode)----链表--两两交换链表中的节点

每日一题(LeetCode)----链表–两两交换链表中的节点 1.题目&#xff08;[24. 两两交换链表中的节点](https://leetcode.cn/problems/spiral-matrix/)&#xff09; 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内…

网站迁移到HTTPS,如何避免内容重复?

我们常说安装SSL证书不是件难事&#xff0c;但将网站迁移到HTTPS的过程却不那么容易。你不是真的在重新建立一个网站&#xff0c;但如果出了差错&#xff0c;百度会误认为这是个新网站&#xff0c;还可能判定你的网站内容重复。原因归结于你将使用不同的协议来呈现整个网站。HT…

python内容榜第三名

这是家常帖。 最近沉迷整理知识&#xff0c;和大家一起共同学习&#xff0c;共同进步。 越来越爱写博客被大家阅读认可的感觉了。我辛苦学习总结来的成果被大家喜爱。 今天荣登python领域内容榜 榜三&#xff0c;给了我很大的信心去坚持做这件事&#xff0c;知识传播&#xf…

CTF-栈溢出-基本ROP-【ret2syscall】

文章目录 ret2syscallBxMCTF 2023 Anti-Libcmainwrite_bufflush_obufreadintread_buf 思路exp ret2syscall 即控制程序执行系统调用&#xff0c;获取 shell。 BxMCTF 2023 Anti-Libc main write_buf 写入字符的&#xff0c;待会输出 flush_obuf 把字符输出到屏幕 read…

前景一片蓝海,Android音视频开发必备基础知识汇总

转瞬间&#xff0c;2023 已慢慢步入深冬&#xff0c;回首过去一年&#xff0c;音视频技术在经历一番风浪的侵袭过后&#xff0c;变得逐渐相对平静下来。 “内卷”之外&#xff0c;大家似乎更多了一份“理性”指导我们去做一些正确的事&#xff0c;追求技术在商业中的更高价值。…

华为ac+fit无线2层漫游配置案例

ap的管理dhcp在ac上&#xff0c;业务dhcp在汇聚交换机上、并且带2层漫游 R1: interface GigabitEthernet0/0/0 ip address 11.1.1.1 255.255.255.0 ip route-static 12.2.2.0 255.255.255.0 11.1.1.2 ip route-static 192.168.0.0 255.255.0.0 11.1.1.2 lsw1: vlan batch 100…

[AutoSar]在Davinci Configurator中导入Dbc Cdd 文件

目录 关键词平台说明一、实现步骤1.1 添加相关模块1.2 导入文件1.3 加载完成后点next而不是finish1.4 更新配置1.5 解决错误 关键词 嵌入式、C语言、autosar 平台说明 项目ValueOSautosar OSautosar厂商vector芯片厂商TI编程语言C&#xff0c;C编译器HighTec (GCC) 一、实现…

SpringCloud原理-OpenFeign篇(二、OpenFeign包扫描和FeignClient的注册原理)

文章目录 前言正文一、从启动类开始二、EnableFeignClients 的源码分析三、Import FeignClientsRegistrar 的作用四、FeignClientsRegistrar#registerFeignClients(...)五、饥饿注册&懒注册 FeignClientsRegistrar#registerFeignClient(...)六、通过Holder真正注册beanDefi…

kafka原理看这一篇就够了

为何使用消息队列 异步。接口方式实现多个系统协作&#xff0c;如图A系统作为用户请求接收方&#xff0c;需要调用多个系统的接口&#xff0c;这些接口还有可能是在A系统里同步调用&#xff0c;所以最后的接口耗时是多个系统接口耗时的总和&#xff1b;mq方式则可以异步发送消…

终于有人把数据资产入表知识地图总结出来了,轻松看懂

在当前数字化的浪潮下&#xff0c;数据已经成为劳动、土地、知识、技术以后的第五大生产要素&#xff0c;“数据就是资源”已成为共识。如今数据资产“入表”已成定局&#xff0c;数据资产化迫在眉睫。 2023年8月21日&#xff0c;财政部正式印发《企业数据资源相关会计处理暂行…

[Linux] 进程入门

&#x1f4bb;文章目录 &#x1f4c4;前言计算机的结构体系与概念冯诺依曼体系结构操作系统概念目的与定位 进程概念描述进程-PCBtask_struct检查进程利用fork创建子进程 进程状态进程状态查看僵尸进程孤儿进程 &#x1f4d3;总结 &#x1f4c4;前言 作为一名程序员&#xff0c…

Django学习日志09

choices参数的使用 """对于以上可能被我们列举完的字段我们一般都是选择使用choices参来做""" class UserInfo(models.Model):username models.CharField(max_length64)password models.CharField(max_length32)# 先写一个映射关系gender_cho…

从零开始的搭建指南:开发高效的抖音预约服务小程序

预约服务小程序提高了效率&#xff0c;节省了用户时间。下文&#xff0c;小编将与大家一同探讨如何从零开始打造预约服务小程序。 第一步&#xff1a;明确需求和目标 确定你的小程序主要服务领域是什么&#xff1f;是医疗预约、美容美发、餐厅预订还是其他行业&#xff1f;明…

【C++ 学习 ㊴】- 详解 C++ 的 I/O 流

目录 一、C 的 I/O 流 二、C 的标准 I/O 流 三、C 的文件 I/O 流 一、C 的 I/O 流 C 语言有一套完成数据读写&#xff08;I/O&#xff09;的解决方案&#xff1a; 使用 scanf()、gets() 等函数从键盘读取数据&#xff0c;使用 printf()、puts() 等函数向屏幕输出数据&#…

Web前端—移动Web第三天(移动Web基础、rem、less、综合案例—极速问诊)

版本说明 当前版本号[20231120]。 版本修改说明20231120初版 目录 文章目录 版本说明目录移动 Web 第三天01-移动 Web 基础谷歌模拟器屏幕分辨率视口二倍图适配方案 02-rem简介媒体查询rem 布局flexible.jsrem 移动适配 03-less注释运算嵌套变量导入导出禁止导出 04-综合案例…

【用unity实现100个游戏之16】Unity程序化生成随机2D地牢游戏2(附项目源码)

文章目录 先看看最终效果前言生成走廊生成房间修复死胡同增加走廊宽度获取走廊位置信息集合方法一方法二 源码完结 先看看最终效果 前言 上期已经实现了房间的生成&#xff0c;本期紧跟着上期内容&#xff0c;生成走廊并结合上期内容生成连通的房间。 生成走廊 修改Procedur…

WPF Button点击鼠标左键弹出菜单

目录 ContextMenu介绍WPF实现点击鼠标左键弹出菜单如何禁用右键菜单如何修改菜单样式菜单位置设置 本篇博客介绍WPF点击按钮弹出菜单&#xff0c;效果如下&#xff1a; 菜单的位置、央视可以自定义。 实现技巧&#xff1a;不在xaml里菜单&#xff0c;在按钮左键按下的点击事件里…

Linux系统编程 系统编程概念

1.系统调用 系统调用&#xff08;system call&#xff09;其实是 Linux 内核提供给应用层的应用编程接口&#xff08;API&#xff09;&#xff0c;是 Linux 应用层进入内核的入口。不止 Linux 系统&#xff0c;所有的操作系统都会向应用层提供系统调用&#xff0c;应用程序通过…

每日汇评:美日在两个月低点附近似乎较为脆弱,熊市可能会在FOMC会议纪要公布前暂停

美元/日元跌至两个月低点&#xff0c;并受到多种因素的压力&#xff1b; 美联储鸽派预期和美国债券收益率下降继续令美元承压&#xff1b; 美日利差缩小以及日本央行政策转变的押注提振了日元&#xff1b; 美元/日元货币对在周二持续第四天承受着沉重的卖压&#xff0c;同时也标…