大话数据结构—栈与队列

一、栈的定义

栈是(stack)是限定尽在表尾进行插入和删除操作的线性表。
栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构。

二、进栈出栈变化形式

注意: 并不是最新进栈的元素只能最后处栈。如,我们现在有三个元素一次进栈,次序会有以下5种:
1. 1、2、2进,再3、2、1出,出栈次序为321;
2. 1进,1出,2进,2出,3进,3出,出栈次序为123;
3. 1进,2进,2出,1出,3进,3出,出栈次序为213;
4. 1进,1出,2进,3进,3出,2出,出栈次序为132;
5. 1进,2进,2出,3进,3出,1出,出栈次序为231。

三、栈的顺序存储结构及实现

(一)栈的顺序存储结构
栈是线性表的特例,栈的顺序存储结构也是线性表存储结构的简化。线性表是用数组实现的,用下标为0的那一端作为栈底使栈变化最小。
我们定义一个top变量来指示栈顶元素在数组中的位置。若存储栈的 长度为StackSize,则栈顶位置top必须小于StackSize。当栈存在一个元素时,top=0.因此,通常把空栈的判定条件定位top=-1.

进栈:push;出栈:pop。(就像子弹的压和弹)。
没有涉及循环,两者的时间复杂度均为1.

两栈共享空间:两个类型相同的栈,则可以共享存储空间。让一个栈的栈底为数组的始端,即下标为0处,另一个栈为数组的末端,即下标为数组长度n-1处。这样,两个栈如果增加元素,就是两端点向中间延伸。两个栈见面之时,也就是两个栈指针相差1,即top1+1==top2为栈满。

(二)栈的链式存储结构
栈的链式存储结构,简称为链栈。
链栈的栈顶和单链表的头指针重合,不需要头结点。
对于链栈来说,不存在栈满的情况,除非内存已经没有可以使用的空间。如果真的发生,就是操作系统已经面临死机崩溃的情况,而不是这个链栈是否真的溢出。
对于空栈来说,链表原定义是头指针指向空,那么链栈的空其实就是top=NULL的时候。

对比顺序栈和链栈,它们在时间复杂度上是一样的,均为O(1)。对于空间性能,顺序栈要事先确定一个固定的长度,可能会存在内存空间浪费的问题,但它的优势是存取时定位很方便,而链栈则要求每个元素都有指针域,这同时也增加了一定的内存开销,但对于栈的长度无限制。所以它们的区别和线性表中讨论的一样,如果栈的使用过程中元素变化不可预料,有时候很小,有时候很大,那么最好是用链栈,如果它们的变化在可控范围内,建议使用顺序栈会更好一些。

四、栈的作用

有的人可能会问,用数组或链表直接实现功能不就行了吗?为什么还要引入栈这个数据结构呢?
其实这和我们明明有两只脚可以走路,干嘛还要乘汽车、火车、飞机一样。理论上,陆地上的任何地方,你都是可以用双脚走到的,可那需要多长时间和精力呢?我们更关注的是到达而不是如何去的问题。
栈的引入简化了程序设计的问题,划分了不同关注层次,使得思考范围缩小,更加聚焦于我们要解决的核心问题。反之,像数组等,因为要分散精力去考虑数组下标的增减问题,反而掩盖了问题的本质。
所以,现在的许多高级语言,比如Java,C#等都有对栈结构的封装,你可以不关注它的实现细节,就可以直接使用Stack的push和pop方法,非常方便。

五、栈的应用

(一) 递归
斐波那契数列
(二)四则运算表达式求值
后缀(逆波兰)表示法:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。
中缀表示法:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为中缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号有优先级不高于栈顶符号(乘除有限加减)则栈顶元素依次出栈并输出,并将当前符号进栈,直到最终输出后缀表达式为止。

队列

一、队列定义

队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。

二、队列的抽象数据类型

同样是线性表,队列也有类似线性表的各种操作,不同的就是插入数据只能在队尾进行,删除数据只能在队头进行。

三、循环队列

队列也有线性表的两种存储方式:顺序存储和链式存储。
入队操作是在队尾增加一个元素,时间复杂度为O(1)。但是,出队时,如果规定队列中的元素都放在前n个位置,则第一个元素出队后,后面的元素都要向前移动,以保证对头不为空,也就是下标为0的位置不为空,此时时间复杂度为O(n)。
但是,我们可以想,如果没有队列的元素都必须放在前n个位置的规定,出队的性能就会大大增加。于是,我们因为两个指针,front指向对头元素,rear指针指向队尾的下一个元素,当front==rear,队列为空。这样,当出队时,只需移动front指针即可。但是,这样也会有一个问题,一个队列不可能只有出队,当继续进行入队操作致使队尾已经填满,rear指针指向队列外时,继续入队就可能产生数组越界的错误。但是,由于前面已经进行过出队操作,所以这个队列前面会有空位置,这种现象称为“假溢出”。这里举个例子,现实生活中,当你上了一辆公交车,发现前面有两个空位置,但后排的座位都已经满了。这是,你不会告诉自己,后面没座了,立马下车,等待下一辆。我们都不会这么笨,而都会坐在前面的位置。
这时,就引入了循环队列的概念。循环队列就是首尾相接的顺序存储结构。
那么,问题又来了,前面提到当front==rear时,队列为空,但在循环队列中,这个结论显然不成立。所以,如何判断队列是空还是满呢?以下给出两种方法:
1. 设置一个标志变量flag,当front==rear,且flag=0时队列为空,当front==rear,且flag=1时队列满。
2. 当队列空时,条件就是front=rear,当队列满时,我们修改条件,保留一个元素空间。也就是说,队列满时,数组中还有一个空闲单元。
我们来重点讨论第二种方法,由于rear可能比front大,也可能比front小,所以它们只相差一个位置时就是满的情况,但也可能是相差整整一圈。所以,若队列的最大尺寸是QueueSize,那么队满的条件是(rear+1)%QueueSize==front(取模%的目的就是为了整合front和rear大小为一个问题)
通用的计算队列长度的公式为(rear-front+QueueSize)%QueueSize
循环队列的相关条件和公式:
1. 队空条件:rear==front
2. 队满条件:(rear+1) %QueueSIze==front,其中QueueSize为循环队列的最大长度
3. 计算队列长度:(rear-front+QueueSize)%QueueSize
4. 入队:(rear+1)%QueueSize
5. 出队:(front+1)%QueueSize
到这里,大家可以发现,但是顺序存储,若不是循环队列,算法的时间性能是不高的,但循环队列有面临着数组可能会溢出的问题,所以我们还需要研究一样不需要担心队列长度的链式存储结构。

四、队列的链式存储结构及实现

队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾尽头出而已,称为链队列。将队头指针指向链队列的头结点,队尾指针指向终端结点。
空队列是,front和rear都指向头结点。
入队操作:就是在链尾插入结点。
出队操作,就是头结点的后继结点出队,将头结点的后继改为它后面的结点,若链表除头结点外只剩一个元素时,则需将rear指向头结点。

对比循环队列和链队列,时间上,其实它们基本操作都是常数时间,即都为O(1)的。不过循环队列是事先申请好空间,使用期间不释放,而对于链队列,每次申请和释放结点也会存在一些时间开销,如果入队出队频繁,则两者还是存在细微差异。对于空间上来说,循环队列不存在这个问题,尽管它需要一个指针域,会产生一些空间上的开销,但也可以接受。所以在空间上,链队列更加灵活。
总的来说,在可以确定队列长度最大值的情况下,建议使用循环队列,如果无法预估队列长度,则用链队列。

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

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

相关文章

【工作感悟】java编程规范pdf下载

前言 要相信,你现在所有的努力和付出都会在将来的某一天回报给你! 首先阿里巴巴作为国内互联网行业的领头羊,培养了一代又一代的IT技术人才,很多想进阿里这些互联网大厂的程序员看中的不仅仅是高薪丰厚的福利待遇,同样…

大话数据结构——串

串(string)是由零个或多个字符组成的有限序列,又名字符串。 字符串有很多函数,replace、ToUpper、ToLower(转小写)、Trim(去掉两边空格)、IndexOf(从左到右查找子串的位…

【工作感悟】全网最经典26道Spring面试题总结

开头 学习如逆水行舟,尤其是IT行业有着日新月异的节奏。 而且现在这个浮躁而又拜金的社会,我相信很多人做技术并非出于热爱,只是被互联网的高薪吸引,毕竟技术岗位非常枯燥,不仅要面对奇奇怪怪的需求,还要…

大话数据结构——树

一、树的定义 树(Tree)是n(n>0)个结点的有限集。 n0又称为空树。在任意一课非空的树中:(1)有且仅有一个特定的称为跟(Root)的结点;(2&#xf…

大话数据结构——图

图(Graph)是由定点的又穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。 一、各种图的定义 …

【工作感悟】达内java大数据课程

前言 其实前几篇文章已经写了好多有关于Spring源码的文章,事实上,很多同学虽然一直在跟着阅读、学习这些Spring的源码教程,但是一直都很迷茫,这些Spring的源码学习,似乎只是为了面试吹逼用,我大概问过一些…

大话数据结构——查找

查找(Searching)是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。 一、顺序表查找 顺序查找又叫线性查找,是最基本的查找技术,它的查找过程是:从表中…

【工作经验分享】java图片转文字

前言 又到一年金九银十之际。 Java作为目前用户最多,使用范围最广的软件开发技术之一。 Java的技术体系主要由支撑Java程序运行的虚拟机,提供各开发领域接口支持的Java,Java编程语言及许多第三方Jvav框架构成。 其中,以Java的虚拟器为今天的着…

数据挖掘工程师的面试问题与答题思路

一个Java程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作。下面简要介绍下类、对象、方法和实例变量的概念。 对象:对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有&…

【干货】java课程实战培训

开头 消息队列 RocketMQ 是阿里巴巴集团基于高可用分布式集群技术,自主研发的云正式商用的专业消息中间件,既可为分布式应用系统提供异步解耦和削峰填谷的能力,同时也具备互联网应用所需的海量消息堆积、高吞吐、可靠重试等特性,…

Java的几个特点

Java语言是简单的: Java语言的语法与C语言和C语言很接近,使得大多数程序员很容易学习和使用。另一方面,Java丢弃了C中很少使用的、很难理解的、令人迷惑的那些特性,如操作符重载、多继承、自动的强制类型转换。特别地&#xff0c…

【干货】mysql建表语句注释

前言 难道程序员的职业生命线是青春饭?答案是的。 35岁考虑转行,然后35岁又成了一个新人,而外国可以做到60岁,啥也不说了,可能是觉得中年大叔油腻,不及小鲜肉便宜,唉,可叹市场更新…

软件测试知识整理

在一个测试计划汇总能包含哪些内容? 答:在一个测试计划中可以包含需要测试的产品的特点和主要功能模块,列出需要测试的功能点,并标明侧重点;测试的策略和记录(测试工具的确认,测试用例等文档模…

【干货】mysql查询重复数据sql

前言 本系列的目的是明明白白、彻彻底底的搞定日期/时间处理的几乎所有case。上篇文章铺设所有涉及到的概念解释,例如GMT、UTC、夏令时、时间戳等等,若你还没看过,不仅强烈建议而是强制建议你前往用花5分钟看一下,因为日期时间处…

【微信小程序】java最简单观察者模式

开头 对于一个Java程序员而言,能否熟练掌握并发编程是判断他优秀与否的重要标准之一。因为并发编程是Java语言中最为晦涩的知识点,它涉及操作系统、内存、CPU、编程语言等多方面的基础能力,更为考验一个程序员的内功。 那到底应该怎么学习并…

操作系统知识点整理

作业 用户在一次解题或一个事务处理过程中要求计算机系统所做工作的集合。它包括用户程序、所需要的数据及控制命令等。作业是由一系列有序的步骤组成的。 进程 一个程序在一个数据集合上的一次运行过程。所以一个程序在不同数据集合上运行,乃至一个程序在同样数…

【性能优化实战】java验证码识别训练

前言 今天刚好有空,跟大家聊聊如何学好算法进大厂。 前两天一个读者和我说,他坚持刷算法题2个月,薪资翻番去了他梦寐以求的大厂,期间面字节跳动还遇到了原题…其实据我所知目前国内的大厂和一些独角兽,已经越来越效仿…

计算机网络知识整理

OSI七层 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。 物理层涉及信道上传输的比特流。 数据链路层的主要任务是加强物理层传输原始比特流的功能,是指对应的网路层显现为一条无错线路。发送包把数据封装在数据帧,按顺序传送出去并处…

吸水间最低动水位标高_体验长安逸动EV460:再也不用为电动车续驶里程焦虑了...

文| 车突突车图腾出品,未经许可,谢绝转载● ● ●人们都在期待碧水蓝天,而且越来越多的消费者也开始践行环保理念,在买车时关注起了纯电动汽车。不过遗憾的是,纯电动汽车目前还没能成为主流。一方面,是因为…

java开发工具包jdk包括哪些

害怕干不过SpringBoot?莫慌,我送你套神级pdf文档 随着 Spring Boot 使用越来越广泛,Spring Boot 已经成为 Java 程序员面试的知识点,很多同学对 Spring Boot 理解不是那么深刻,经常就会被几个连环追问就给干趴下了&am…