数据结构 栈

目录

前言

一,栈的基本介绍与定义

二,数组实现栈

三,链表实现栈

 四,栈的应用

总结


前言

我们学习了链表,接下来我们就来学习栈,我将会从栈的介绍到实现栈与栈的全部的功能


一,栈的基本介绍与定义

栈( Last In First Out :最先进来的最先出去)

简称:LIFO

1,栈的属性

最先进来的元素最后进去,可以抽象为我们现实中放东西,每次访问栈的元素的时候,只可以访问站的顶部(任何元素都是只可以从最顶部进行插入和删除等一系列的操作)

可以类似于羽毛球筒,先放进去最后拿出来

如果实在难以理解,可以去阅读我的文章,函数栈帧,这些都是必备的知识

2,栈的定义

栈是一个列表或者集合,它有这样的一种限制,插入,删除只能从一段进行,而这个操作的位置我们称为栈顶

基本操作:

1  push( 插入 )   2  pop( 弹出 )   3  top( 返回栈顶元素 )   4  empty( 是否为空 )

时间复杂度O( n )

3,操作的实际情况

这个就是我们再实际操作栈的过程,每个函数都是有着自己的作用,我们只需要根据函数进行自己想要的操作就好了,STL库里面是有给stack这个类的,可以直接调用并使用

4,实际应用

————可以用来帮助我们执行函数

————递归

————编译器的撤销操作

————编译器里面的括号操作( 如: {  }     [  ]    (  ) )

二,数组实现栈

1,插入与删除

伪代码思想

我创建一个数组,此时此刻当数组为空栈的时候,有一个top指针是再-1处的,然后我们插入数据的时候,也是只可以再栈顶插入,只要再A[ top ]处添加元素,我们栈是用来存储临时数据的,不会长期保存,所以我们并不用把刚刚开始初始化在0处的值给删除,直接把栈顶往后移动,利用下一次赋值占上去就好了,这个就是栈的性质

这里我们栈的时间复杂度是O( 1 )

最好的情况是O( 1 ),最坏的情况是O( n ),平均下来就是O( 1 )了

其他的功能

返回栈顶元素

Top( ){ return A[ top ]; }

检查是否为空 

Isempty( ){ 

if( top==-1)return true;

else return fasle; }

2,模拟实现

#include<iostream>
using namespace std;
#define MAX_SIZE 100

int A[MAX_SIZE];
int top = -1;

void push(int x) {
	if (top == MAX_SIZE) {
		cout << "stack overflow" << endl;
		return;
	}
	A[++top] = x;
}

void pop() {
	if (top == -1) {
		cout << "NO element to pop" << endl;
		return;
	}
	top--;
}

int Top() {
	if (top == -1) {
		cout << "NO element in the stack" << endl;
		return 0;
	}
	return A[top];
}

void IsEmpty() {
	if (top == -1) {
		cout << "Stack is empty" << endl;
	}
	else {
		cout << "Stack not is empty" << endl;
	}
}

void print() {
	int i = 0;
	for (i = top;i >= 0;i--) {
		cout << A[i] << endl;
	}
}

int main() {
	push(2);
	push(3);
	push(78);
	push(89);
	IsEmpty();
	pop();
	print();
	return 0;
}

分别模拟了push插入   pop弹出   top返回栈顶元素   isempty是否为空

push插入:     就是利用数组下角标进行索引,然后把值放入到对应的位置,记得top的值要1改变

pop弹出:       就是利用top--来是实现打印的具体位置,记得栈是不需要删除原本在那里的值的

top返回栈顶: 就是利用return返回A[ top ]即可

isempty检查: 就是我们利用top的值,这个栈顶的值还是原来的那个值就是为空了

三,链表实现栈

我们使用链表的话,由于栈只可以在栈顶进行插入与删除,所以我们要选择一端作为栈顶,所以有两种方法,一种是头插法还有一种是尾插法,由于头插法的时间复杂度是O( 1 )而尾插法的时间复杂度是O( n )所以我们选择头插法

这个实现就是链表的头插法罢了 

#include<iostream>
#include<new>
using namespace std;

struct Node {
	int data;
	struct Node* Next;
};
Node *head;

void insert(int a) {
	Node* temp = new Node;
	temp->data = a;
	temp->Next = head;
	head = temp;
}

void print() {
	Node* a = head;
	while (a != NULL) {
		cout << a->data << " ";
		a = a->Next;
	}
}

int main() {
	Node* temp1 = new Node;
	Node* temp2 = new Node;
	Node* temp3 = new Node;

	temp1->data = 1;
	temp2->data = 2;
	temp3->data = 3;

	head = temp1;
	temp1->Next = temp2;
	temp2->Next = temp3;
	temp3->Next = NULL;
	
	insert(4);
	print();
}

这个代码很好理解,也就是头插法,很简单

 四,栈的应用

1,反转一个字符串

我们用c++来实现栈来打印这个字符串

再STL库里面是提供stack的,所以我们只需要引用这个头文件就好了

#include<iostream>
#include<stack>
using namespace std;

char str[6] = "hello";

void Reverse() {
	stack<char>S;
	for (int i = 0;i < 5;i++) {
		S.push(str[i]);
	}
	for (int i = 0;i < 5;i++) {
		str[i] = S.top();
		S.pop();
	}
}

int main() {
	Reverse();
	for (int i = 0;i < 5;i++)
		cout << str[i];
	return 0;
}

我们即使没有学习过STL库,但是这里可以进行简单的记忆,stack<类型>名字,然后这是一个类,类跟结构体是差不多的,所以直接用成员运算符就好了,里面的函数的作用跟上面所讲的是一样的

当然这个不是最优解对于反转字符串,但是是很简答的,我们还有另外一个方法比这个方法更高效

这里用两个指针分别指向头和尾,然后进行交换,有奇数情况和偶数情况,然后进行交换就好了,这个效率比那个更高,这里就不写代码了,这里主要是讲栈,提供一个思路,虽然时间复杂度都是O( n ),但是空间复杂度这个方法更少

2,反转一个链表

#include<iostream>
#include<stack>
using namespace std;

struct Node {
	int data;
	Node* Next;
};
Node* head;

void Reverse() {
	Node* temp = head;
	stack<Node*>S;
	while (temp != NULL) {
		S.push(temp);
		temp = temp->Next;
	}
	temp = S.top();
	head = temp;
	while (!S.empty()) {
		temp->Next = S.top();
		S.pop();
		temp = temp->Next;
	}
	temp->Next = NULL;
}

void print() {
	Node* temp = head;
	while (temp != NULL) {
		cout << temp->data << "  ";
		temp = temp->Next;
	}
}

int main() {
	head = NULL;
	Node* temp1 = new Node;
	temp1->data = 1;
	temp1->Next = NULL;

	Node* temp2 = new Node;
	temp2->data = 2;
	temp2->Next = NULL;

	Node* temp3 = new Node;
	temp3->data = 3;
	temp3->Next = NULL;

	Node* temp4 = new Node;
	temp4->data = 4;
	temp4->Next = NULL;

	temp1->Next = temp2;  temp2->Next = temp3;  temp3->Next = temp4;
	head = temp1;

	 Reverse();
	 print();
}

这里我们的stack设置的是Node*类型,那么为什么设置为这个呢?

  • 链表中的每个节点是动态分配的指针对象
    在链表结构中,通常每个节点是一个动态分配的结构体或类对象 (Node),这些节点通过指针相互连接。Node* 表示一个指向链表节点的指针。如果你只使用 Node 而不是 Node*,你将需要存储整个节点对象,而不是存储指向它的指针。

  • 节省内存开销
    如果你用 stack<Node>,每次调用 S.push(temp) 时,整个 Node 对象都会被拷贝并存储到栈中。这不仅浪费内存,而且对拷贝构造函数或赋值操作符有较高要求。而 stack<Node*> 只存储指针,效率更高,因为它只存储地址,而不是拷贝整个对象。

  • 避免深拷贝问题
    如果 Node 的成员变量中有动态分配的内存(如指针成员变量),使用 stack<Node> 可能会引发深拷贝问题(对象被复制时,动态内存区域需要正确地处理分配和释放)。而用 Node*,栈只存储地址,避免了额外的复杂性。

  • 与链表的实现方式一致
    在链表中,节点是通过 Node* 相互连接的,temp->Next 的类型也是 Node*。为了让栈与链表的数据结构统一,使用 stack<Node*> 是更合理的选择。

 总结:

1,你要存储的是这个节点,而不是这个节点的指针

            2,如果真的是存储了节点,那么就加大了内存的开销,因为你有添加了一个副本,如果用指针就可以减少内存的开销

            3,避免深度拷贝,就是为了减少复杂性,我们把这个栈里面直接存储地址,释放也很好释放

            4,书写美观,因为你可以用->这个符号,可以统一

3,检查括号的匹配性

思路:我们只需要把左括号放入栈里面,然后检测右括号,如果最终栈为空或者由括号匹配不上就直接暴异常就好了,因为你放括号的顺序一定是和你匹配括号的顺序是一样的,这里就讲解思路,读者可以下去自己写写代码


总结

我们介绍了栈的基本定义和介绍

然后分别用数组和链表来实现栈

最后展现了栈的应用

总的来说,栈就是适合反转某个东西,因为你放进去永远与你拿出来是相反的,还可以利用栈来检查对称性

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

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

相关文章

用Python绘制一只懒羊羊

目录 一、准备工作 二、Turtle库简介 三、绘制懒羊羊的步骤 1. 导入Turtle库并设置画布 2. 绘制头部 3. 绘制眼睛 4. 绘制嘴巴 5. 绘制身体 6. 绘制四肢 7. 完成绘制 五、运行代码与结果展示 六、总结 在这个趣味盎然的技术实践中,我们将使用Python和Turtle图形…

Couchbase UI: Indexes

在Couchbase中&#xff0c;索引的这些指标可以帮助你评估索引的性能和状态。下面是每个指标的详细解释&#xff0c;以及如何判断索引的有效性&#xff1a; 1. Index Name&#xff08;索引名称&#xff09; 描述&#xff1a;每个索引都有一个唯一的名称。这个名称通常会包括表…

修改maven的编码格式为utf-8

1.maven默认编码为GBK 注:配好MAVEN_HOME的环境变量后,在运行cmd. 打开cmd 运行mvn -v命令即可. 2.修改UTF-8为默认编码. 设置环境变量 变量名 MAVEN_OPTS 变量值 -Xms256m -Xmx512m -Dfile.encodingUTF-8 3.保存,退出cmd.重新打开cmd 运行mvn -v命令即可. 源码获取&…

Visual Studio Code修改terminal字体

个人博客地址&#xff1a;Visual Studio Code修改terminal字体 | 一张假钞的真实世界 默认打开中断后字体显示如下&#xff1a; 打开设置&#xff0c;搜索配置项terminal.integrated.fontFamily&#xff0c;修改配置为monospace。修改后效果如下&#xff1a;

MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log

文章目录 一、前言1.1 MySQL体系结构1.2 MySQL日志分类1.3 其他几种日志1.3.1 查询日志1.3.2 慢查询日志1.3.3 错误日志 二、bin log 二进制日志2.1 bin log简介2.2 binlog日志格式2.3 日志删除2.4 写入/刷盘机制 三、undo log 回滚日志3.1 undo log简介3.2 隐藏字段 —— 事务…

electron打包客户端在rk3588上支持h265硬解

目录 前言 chromium是如何支持h265硬解 electron/chromium第一次编译 electron/chromium第二次编译 前言 我们的客户端程序是用electron打包的前端程序&#xff0c;其在rk3588主机上的linux环境运行。之前使用客户端查看h264编码的视频直播是没有问题的&#xff0c;但视频源…

关于CAN(FD)转以太网详细介绍

一、功能描述 CANFD 完全向下兼容 CAN &#xff0c;以下统称 CAN(FD) 。 SG-CAN(FD)NET-210 是一款用来把 CANFD 总线数据转为网口数据的设备。 网口支持 TCP Sever 、 TCP Client 、 UDP Sever 、 UDP Client 四种模式。 可以通过软件配置和 Web 网页配置。 两路…

DRG_DIP 2.0时代医院程序结构转型与数据结构优化研究

一、引言 1.1 DRG_DIP 2.0 改革背景与意义 医保支付方式改革在医疗保障制度改革中占据着极为关键的地位,是推动医疗领域变革的核心力量。它犹如一把精准的手术刀,对医疗资源的合理分配、医疗服务质量的稳步提升以及医疗费用的有效控制起着决定性作用。在这一改革进程中,DR…

Arcgis国产化替代:Bigemap Pro正式发布

在数字化时代&#xff0c;数据如同新时代的石油&#xff0c;蕴含着巨大的价值。从商业决策到科研探索&#xff0c;从城市规划到环境监测&#xff0c;海量数据的高效处理、精准分析与直观可视化&#xff0c;已成为各行业突破发展瓶颈、实现转型升级的关键所在。历经十年精心打磨…

洛谷 B2031:计算三角形面积 ← 叉积

【题目来源】 https://www.luogu.com.cn/problem/B2031 【题目描述】 平面上有一个三角形&#xff0c;它的三个顶点坐标分别为 (x1, y1)&#xff0c;(x2, y2)&#xff0c;(x3, y3)&#xff0c;那么请问这个三角形的面积是多少。 【输入格式】 输入仅一行&#xff0c;包括 6 个…

从 Spark 到 StarRocks:实现58同城湖仓一体架构的高效转型

作者&#xff1a;王世发&#xff0c;吴艳兴等&#xff0c;58同城数据架构部 导读&#xff1a; 本文介绍了58同城在其数据探查平台中引入StarRocks的实践&#xff0c;旨在提升实时查询性能。在面对传统Spark和Hive架构的性能瓶颈时&#xff0c;58同城选择StarRocks作为加速引擎&…

Kafak 单例生产者实现-C#操作

前面写了一篇入门操作的文章,因为工作需要,简单修改了下如何实现单例生产者。 Kafka入门-C#操作_c# kafka-CSDN博客文章浏览阅读1.6k次,点赞20次,收藏9次。2).报错:“kafka.zookeeper.ZooKeeperClientTimeoutException: Timed out waiting for connection while in state…

【GoLang】利用validator包实现服务端参数校验时自定义错误信息

在C/S架构下&#xff0c;服务端在校验请求参数时&#xff0c;若出现参数错误&#xff0c;要响应给客户端一个错误消息&#xff0c;通常我们会统一响应“参数错误”。 但是&#xff0c;如果只是一味的提示参数错误&#xff0c;我并不知道具体是哪个参数错了呀&#xff01;能不能…

机器学习 vs 深度学习

目录 一、机器学习 1、实现原理 2、实施方法 二、深度学习 1、与机器学习的联系与区别 2、神经网络的历史发展 3、神经网络的基本概念 一、机器学习 1、实现原理 训练&#xff08;归纳&#xff09;和预测&#xff08;演绎&#xff09; 归纳: 从具体案例中抽象一般规律…

Unity git版本管理

创建仓库的时候添加了Unity的.gitignore模版&#xff0c;在这个时候就能自动过滤不需要的文件 打开git bash之后&#xff0c;步骤git版本管理-CSDN博客 如果报错&#xff0c;尝试重新进git 第一次传会耗时较长&#xff0c;之后的更新就很快了

【JWT】jwt实现HS、RS、ES、ED签名与验签

JWT 实现 HS、RS、ES 和 ED 签名与验签 签名方式算法密钥类型签名要点验签要点HSHMAC-SHA256对称密钥- 使用 crypto/hmac 和对称密钥生成 HMAC 签名- 将 header.payload 作为数据输入- 使用同一密钥重新计算 HMAC 签名- 比较计算结果与接收到的签名是否一致RSRSA-SHA256公钥 …

【Bug 记录】el-sub-menu 第一次进入默认不高亮

项目场景&#xff1a; 项目场景&#xff1a;el-sub-menu 第一次进入默认不高亮 问题描述 例如&#xff1a;sub-menu 的 index 后端默认传过来是 number&#xff0c;我们需要手动转为 string&#xff0c;否则会有警告&#xff0c;而且第一次进入 sub-menu 默认不高亮。 解决方…

LLM幻觉(Hallucination)缓解技术综述与展望

LLMs 中的幻觉问题&#xff08;LLM 幻觉&#xff1a;现象剖析、影响与应对策略&#xff09;对其可靠性与实用性构成了严重威胁。幻觉现象表现为模型生成的内容与事实严重不符&#xff0c;在医疗、金融、法律等对准确性要求极高的关键领域&#xff0c;可能引发误导性后果&#x…

挖掘机的市场现状和发展前景:全球增长潜力,重塑基础设施建设新篇章

引言&#xff1a;工程机械的心脏&#xff0c;挖掘机的崛起之路 在现代化建设的浪潮中&#xff0c;挖掘机作为工程机械领域的核心设备&#xff0c;正以其强大的作业能力和广泛的应用场景&#xff0c;成为推动全球基础设施建设不可或缺的力量。从高速公路到大型矿场&#xff0c;…

算法每日双题精讲 —— 二分查找(山脉数组的峰顶索引,寻找峰值)

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 别再犹豫了&#xff01;快来订阅我们的算法每日双题精讲专栏&#xff0c;一起踏上算法学习的精彩之旅吧&#x1f4aa; 在算法的…