【栈和队列】

news2024/10/7 7:30:24

目录

1,栈(Stack)

1.1 概念

1.2 栈的使用

1.3 栈的模拟实现

1.4 栈的应用场景

1.5 概念区分

1.6  使用链表来实现栈

2, 队列(Queue)

2.1 概念

2.2 队列的使用

2.3 队列模拟实现

3,双端队列 (Deque)

4,面试题

4.1 用队列实现栈

4.2 用栈实现队列


1,栈(Stack)

1.1 概念

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。

出栈:栈的删除操作叫做出栈。出数据在栈顶。

1.2 栈的使用

push():叫做压栈,往栈里面放元素

查看push源代码,是有返回值的,他的返回值代表入栈的元素

pop():叫做出栈,弹出栈顶元素

此时就弹出了56

我们查看pop的源代码,他的返回值代表出栈的元素

peek():获取栈顶元素,但是不删除

源码:

empty():检测栈是否为空

源码:

stack可以调用empty可以理解,为什么可以调用isEmpty,Stack里面并没有这个方法呀!!

观察到Stack继承了Vector,isEmpty方法在Vector这个类当中,所以也继承了Vector类当中的方法

1.3 栈的模拟实现

创建一个类,叫做MyStack,自己来实现一个栈

那怎么来表示这个栈呢?

可以用一个数组来表示,每次往数组的最后一个存储元素,删也是删最后一个

1,push

怎么来放呢,就可以用到前面讲过的,定义一个usedSize来记录元素个数,并在对应位置存放元素,usedSize为0,在0下标存放一个元素,记录这个元素(usedSize++),在存放usedSize++下标位置的元素,再次记录这个元素(usedSize++),依次进行!!!

还要考虑数组满了的情况,对其进行扩容!

2,pop    弹出一个元素

首先如果是空的,就不能弹出元素,可以抛一个异常

可以发现,当usedSize为4的时候,我们需要弹出3下标的元素,即弹出elem[ usedSize -1 ]即可

3,peek   获取栈顶元素

这就是我们自己实现的一个栈。

可以将这个自己实现的栈变成泛型:

1.4 栈的应用场景

1,改变元素的序列

2,将递归转化为循环(一般情况下会用栈)

比如:逆序打印链表

非递归实现:就可以申请一个栈,这个栈里面就去放节点,然后进行出栈打印,即为逆序打印

3,括号匹配

描述:给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

在括号匹配的时候,一定是最后一个左括号和第一个右括号是否匹配,如何找到最后一个左括号呢?使用栈来完成。

情况一:如果是在括号匹配的时候,申请一个栈,定义一个 i 下标来遍历字符串。遇到一个左括号把这个左括号放到栈里面,i++,又遇到一个左括号放到栈里面,当遇到右括号的时候,就和当前的栈顶元素去匹配。当遇到右括号时,让当前的这个右括号与栈顶元素进行匹配,匹配成功,就让当前栈顶元素进行出栈,i++,再去判断右括号与当前栈顶元素是否匹配,匹配成功,就让当前栈顶元素进行出栈。即括号是匹配的情况下,最后栈为空且字符串以遍历完成。

情况二:如果不匹配,同上只要是左括号都放到栈里面,当遇到右括号时,与栈顶元素不匹配,返回false

情况三:字符串还没有遍历完,栈已经空了的情况。如下面这种,左括号放到栈里面,当遇到右括号时,与栈顶元素匹配,但是 i 没有遍历完,栈已经空了

情况四:左括号放到栈里面,遇到右括号时,与栈顶元素进行匹配,弹出栈顶元素后,i 已经遍历完了,但是栈里面还有元素

4,逆波兰表达式求值

逆波兰表达式又叫做后缀表达式(将运算符写在操作数之后)

例如:

中缀表达式(平常所看到的表达式):2+(3*5)

对应的后缀表达式:235*+

推导:

运算:

题目描述:

示例:

给的是一个字符串数组,放到栈里面的应该是整型,所以要将数字字符转为整型。

所以可以写一个方法,判断拿到这个字符串是否为运算符

5,栈的压入,弹出序列 (上面第一题)

描述:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

6,最小栈

描述:设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

在常数时间内(时间复杂度为O(1))检索到最小值,一个栈是不能完成的,需要申请两个栈,一个普通栈,一个最小栈。

那如何能拿到一个最小栈呢?

1.5 概念区分

栈、虚拟机栈、栈帧有什么区别呢?

栈是一种数据结构。

虚拟机栈:如定义的局部变量就存于虚拟机栈当中。

栈帧:调用方法的时候为他开辟的一块内存。

至此:刚刚实现的栈或者说Java集合类的Stack底层是一个数组。这种栈叫做顺序栈!!!

1.6  使用链表来实现栈

首先栈遵循后进先出的原则,并且时间复杂度为O(1)

如果是单链表,那么入栈和出栈最好从链表头进行入栈和出栈。

相反如果链表的尾部进行出栈入栈时间复杂度为O(N)。

如果是双向链表来实现栈,那么复杂度均是O(1),如果以后要用到链式栈,使用双向链表会更好!

那么就可以直接当栈来使用。

为什么会报错?因为List这个接口没有实现push这个方法,要用LinkedList来引用这个对象。

这样就可以直接使用了,我们查看push,pop的源码。源码里面采用的是头插和头删!

所以可以拿数组实现栈,也可以拿链表实现栈。

如果要用数组实现的栈就用Stack这个类。

要用链式栈,使用LinkedList引用,或者Deque(叫做双端队列,下面会讲到)引用就可以当中栈来使用。

2, 队列(Queue)

2.1 概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头 (Head/Front)

例如:食堂打饭排队,先排队的先打饭

2.2 队列的使用

在Java中,Queue是个接口,底层是通过链表实现的。

三个红色框框为一组,三个绿色框框为一组,两组从结果上来说没有什么区别。

要看他们的区别,如add和offer都是入队操作。

add和offer都是向队列中添加一个元素,一些队列有大小限制,因此如果想在一个满的队列中加入一个新项:

  • add:此时调用 add() 方法就会抛出一个 unchecked 异常
  • offer:此时调用 offer() 方法会返回 false,可以在程序中进行有效的判断。

2.3 队列模拟实现

1,用链表来实现(源码里面用的链式实现)

首先队列遵循先进先出的原则,那么入队就可以从尾巴入,出队就可以从头部出

也可以入队从头部入,出队从尾巴出

我们可查看源码的offer:调用了add方法               进入add方法:源码实现的是尾插法

模拟实现Queue

2,用数组来实现队列

首先对头叫做first,队尾叫做last。

此时last遍历完了,数组满了

假设现在对头可以出,出掉12 23,那么我的对头为34。但是此时0,1下标还可以放元素,数组并没有满!!!

我们在数组满的时候让last指向first。可能first和last相遇代表数组为空,不管空还是满(后面解决),先让last走回来,此时就可以再次存放元素了。

那么这个数组就不是简单的数组了,这个数组循环利用了,把这个队列叫做循环队列。

相当于把这个数组卷起来!!! 现在这个数组是这个样子。

开始存放元素:

满或者空也不一定是在0位置,有可能last在7的时候first就进行出,一直出就可能是在7位置相遇。也可能last在7位置first就开始出,出到2位置又开始存,就也可能在2位置相遇。 

到目前位置:相遇的时候是空的,相遇的时候也可能是满的!!!没有解决问题。

如何判断空和满!

方案一:

usedSize!!!放一个数据usedSize++,us == 0 为空,us == 数组长度为满。

方案二:

定义一个Boolean类型的flg = false 第一次相遇为false,第二次相遇为true。以标记的形式来判断。

方案三:(此代码用方案三实现)

浪费一个空间。也就是假如你的数组长度是8,但是最多只放7个元素。

即last和first相遇时为空,last的下一个为first就为满

如何让last或者first从7走到0,不能是last++或者first++,这样会导致数组下标越界,我们可给出一个公式:last = (last + 1)% 数组长度

代码实现:

首先此时代码有点错误

3,双端队列 (Deque)

双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。 那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。

普通的队列只能从队尾进对头出,如果是双端队列,这个队列两边都可以进出。

有头插,尾插,还有头删尾删

LinkedList是双端队列的链表形式。

ArrayDeque是双端队列的线性实现(操作的是数组)。 

对于这两个类(LinkedList,ArrayDeque),可以当作栈使用,也可以当作队列使用

4,面试题

4.1 用队列实现栈

首先一个队列是不能实现栈的,这两个是相互矛盾的,一个是先进先出,一个是先进后出。

既然一个队列达不到要求,就用两个队列来实现栈。

top:

代码实现:

4.2 用栈实现队列

还是一样的,一个栈是不能实现队列的。要申请两个栈。

代码实现:

至此,栈和队列都讲完了!!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

r2frida:基于Frida的远程进程安全检测和通信工具

关于r2frida r2frida是一款能够将Radare2和Frida的功能合二为一的强大工具,该工具本质上是一个Radare2的自包含插件,可以帮助广大研究人员利用Frida的功能实现对目标进程的远程安全检测和通信管理。 Radare2项目提供了针对逆向工程分析的完整工具链&…

利用golang_Consul代码实现Prometheus监控目标的注册以及动态发现与配置

文章目录 前言一、prometheus发现方式二、监控指标注册架构图三、部分代码展示1.核心思想2.代码目录3、程序入口函数剖析4、settings配置文件5、初始化配置文件及consul6、全局变量7、配置config8、公共方法目录common9、工具目录tools10、service层展示11、命令行参数12、Make…

使用 axios 进行 HTTP 请求

使用 axios 进行 HTTP 请求 文章目录 使用 axios 进行 HTTP 请求1、介绍2、安装和引入3、axios 基本使用4、axios 发送 GET 请求5、axios 发送 POST 请求6、高级使用7、总结 1、介绍 什么是 axios axios 是一个基于 promise 的 HTTP 库,可以用于浏览器和 Node.js 中…

十大经典排序算法——选择排序和冒泡排序

一、选择排序 1.基本思想 每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据全部排完。 2.直接选择排序 (1) 在元素集合arr[i] — arr[n - 1]中选择关键妈的最大(小…

目标检测数据集 - 手机屏幕表面表面缺陷检测数据集下载「包含VOC、COCO、YOLO三种格式」

数据集介绍:手机屏幕表面缺陷检测数据集,真实采集高质量手机屏幕表面含缺陷图片数据,数据集含多款不同型号和品牌的手机屏幕表面图片数据,包括苹果手机屏、三星手机屏、华为手机屏等数据。数据标注标签包括 Bubble 气泡/水滴、Scr…

google gemini1.5 flash视频图文理解能力初探(一)

市面能够对视频直接进行分析的大模型着实不多,而且很多支持多模态的大模型那效果着实也不好。 从这篇公众号不只是100万上下文,谷歌Gemini 1.5超强功能展示得知,Gemini 1.5可以一次性处理1小时的视频、11小时的音频或100,000行代码&#xff0…

修改源码,打patch包,线上环境不生效

1.首先看修改的源码文件是否正确 在node_modules中,找对应的包,然后查看包中package.json 的main和module。如果用require引入,则修改lib下面的组件,如果是import引入则修改es下面的文件 main 对应commonjs引入方式的程序入口文件…

python-04

str.spilt() str.spilt(str" ", num string.count(str)); str:分隔符,默认为所有的空字符,包括空格、换行符"\n"、制表符"\t"等。 num:分隔次数 str "小时候 总有他们在耳边叮咛嘱咐 小…

Redis 高可用 sentinel

简介 Sentinel提供了一种高可用方案来抵抗节点故障,当故障发生时Redis集群可以自动进行主从切换,程序可以不用重启。 Redis Sentinel集群可以看成是一个Zookeeper集群,他是Redis集群高可用的心脏,一般由3-5个节点组成&#xff0…

195.回溯算法:分割回文串(力扣)

代码解决 class Solution { public:vector<string> res; // 当前路径&#xff0c;用于存储一个可能的回文分割结果vector<vector<string>> result; // 存储所有可能的回文分割结果// 判断子串 s[left:right] 是否是回文bool isPalindrome(const string& …

示例:WPF中如何绑定ContextMenu和Menu

一、目的&#xff1a;开发过程中&#xff0c;有些模块的右键ContextMenu菜单是需要动态显示的&#xff0c;既是根据不同条件显示不同的菜单&#xff0c;很多是通过代码去生成ContextMenu的MenuItem&#xff0c;本文介绍通过绑定的方式去加载ContextMenu&#xff0c;Menu菜单栏的…

Java面试题:数据库索引

数据库索引 索引:index 帮助mysql高效获取数据的数据结构,在数据之外,数据库系统还维护着满足特定查找算法的数据结构(B树),这些数据结构以某种方式引用(指向数据),这样就可以在数据结构上实现高级查找算法 将数据以树的方式进行存储,提高查找效率 索引的底层结构 使用B树 …

C语言中的进制转换

基础概念 进制又称数制&#xff0c;是指用一组固定的符号和统一的规则来表示数值的方法&#xff0c;在C语言中&#xff0c;可以使用不同的前缀来表示不同的进制&#xff1a; 二进制&#xff1a;以0b或0B为前缀&#xff08;部分编译器可能不支持&#xff09;八进制&#xff1a…

使用Inno Setup 5.5制作软件安装包-精品(二)

上一篇 使用Inno Setup 6制作软件安装包&#xff08;一&#xff09;-CSDN博客 文章简单的说了一下使用Inno Setup 6制作软件安装包&#xff0c;具体有很多的细节&#xff0c;都可以参考上篇的案例。本节说一下&#xff0c;Inno Setup 5 增强版制作软件精品安装包&#xff0c;…

在线随机密码生成工具

对于运维工作&#xff0c;经常需要生产随机密码&#xff0c;这里介绍一款在线生成密码工具&#xff0c;支持配置密码组合类型&#xff0c;如数字、字母大小写、特殊字符等&#xff0c;还能排除某些特殊字符。 在线随机密码生成工具 https://tool.hiofd.com/random-string-gen…

STL迭代器的基础应用

STL迭代器的应用 迭代器的定义方法&#xff1a; 类型作用定义方式正向迭代器正序遍历STL容器容器类名::iterator 迭代器名常量正向迭代器以只读方式正序遍历STL容器容器类名::const_iterator 迭代器名反向迭代器逆序遍历STL容器容器类名::reverse_iterator 迭代器名常量反向迭…

Python的pip切换国内源

&#x1f4da;目录 起因&#xff1a;pip切换国内源&#xff1a;操作永久修改pip配置文件测试永久源配置是否成功 pip其他环境的配置永久源配置 起因&#xff1a; pyCharm安装模块的手出现ModuleNotFoundError: No module named distutils 由于使用pip install distutils下载不了…

ViT:4 Pruning

实时了解业内动态&#xff0c;论文是最好的桥梁&#xff0c;专栏精选论文重点解读热点论文&#xff0c;围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型重新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;…

力扣SQL50 查询近30天活跃用户数 datediff(日期1,日期2)

Problem: 1141. 查询近30天活跃用户数 &#x1f468;‍&#x1f3eb; 参考题解 -- 选择活动日期作为天数&#xff0c;计算每天的唯一活跃用户数 select activity_date as day, count(distinct user_id) as active_users from activity -- 从2019年7月27日开始的30天内 where …

手撕RPC——实现简单的RPC调用

手撕RPC——实现简单的RPC调用 一、场景设计二、设计思路2.1 客户端的设计2.2 服务端的设计2.3 通信设计 三、代码实现3.1 定义用户信息3.2 用户服务接口3.3 用户服务接口实现3.4 定义消息格式3.5 实现动态代理类3.6 封装信息传输类3.7 定义服务端Server接口3.8 实现RpcServer接…