大家好,我王有志又回来啦。关注王有志,回复DSA获取数据结构和算法学习资源。

最近被全链路优化搞得焦头烂额,等抽出时间来和大家分享下我司正在做的“全面提速工程”。

今天我们来学习线性表中最后两种数据结构:栈和队列。它们是两种比较特殊的线性表,相较于数组和链表而言,可以认为它们是“高级”的线性表。

栈和队列的特点

前几天和媳妇聊到大学校门口的美食广场,每到夜晚便人声鼎沸,撸肉串的,喝扎啤的…

Hold on!Hold on!(最近沉迷《中国说唱巅峰对决》hhh)。

羊肉串和扎啤不就是栈和队列吗?你品,你细品。

串肉串的时候,从签子的尖头(栈顶)开始串(入栈),最先串进去的被压倒签子的底部(栈底),而撸串(出栈)也是从尖头开始,最后串进去的却最先被吃掉(后进先出,LIFO,last in first out)。

灌扎啤的时候,从灌口(队尾)灌进去(入队)的扎啤停留在罐底(队首),当你从罐底的水龙头打开的时候,最先流出来(出队)的停留在罐底的那部分(先进先出,FIFO,first in first out)。

我们再来画张图,来看看栈和队列到底“长什么样”。

看起来栈和队队列就是很普通的线性表啊,没什么特别的。

实际上就是这样的,如果限定数组或链表只能在尾部插入和尾部删除,那就是栈。如果只能在头部删除尾部插入,那就是队列。

也正是如此,我们常常称栈和队列为受限线性表,数组和链表为非受限线性表。而栈和队列所允许的操作也是数组和链表所允许操作的子集

栈和队列的ADT

了解了栈和队列后,我们来看看它们都允许哪些操作,这里我们“抄袭”Java中方法的命名习惯给出对应数据结构的ADT,首先是栈:

public interface Stack<E> {/*** 大小*/int size();/*** 是否为空*/boolean isEmpty();/*** 入栈*/ void push(E e);/*** 出栈*/E pop();/*** 查看栈顶数据* 与{@link Stack#pop()}的区别是:* pop会移除栈顶数据* peek不会移除栈顶数据*/E peek();
}

接着是队列:

public interface Queue<E> {/*** 大小*/int size();/*** 是否为空*/boolean isEmpty();/*** 入队*/void add(E element);/*** 出队*/ E poll();/*** 查看队首数据* 与{@link Queue#poll()}的区别是:* poll会移除队首数据* peek不会移除队首数据*/E peek();
}

相较于动态数组和链表,栈和队列的操作就简单很多了,实现起来也非常容易,在这里就不水字数了。你可以基于已经实现过的动态数组和链表去实现,也可以自行实现顺序结构或者链式结构。

附上我实现的栈和队列,欢迎大家一起讨论。

栈的应用

栈这种结构虽然简单,但是在计算机世界中却有着极其重要的作用,其中最耳熟能详的就是调用栈了。

如果对调用栈不熟悉的小伙伴,推荐阅读汤洋老师的文章《Call Stack(调用栈)是什么?》。

调用栈

如果你是Java程序员,相信在面试中你一定被问到过虚拟机栈。没错,Java中的虚拟机栈就是最典型的调用栈之一。

还记得我们在04.编程技巧:从斐波那契数列到递归
中说到尾递归消除时的那张图吗?

main中调用functionAfunctionA调用functionBfunctionB调用functionC,每次调用后都压入到栈中,按照代码的执行逻辑,functionC最先执行完毕,可以从栈中取出,然后functionBfunctionAmain

现在来看,栈的特性是不是完美契合计算机中的调用顺序?

撤销栈

作为一名资深的“CV工程师”,除了Ctrl+CCtrl+V外,我还会经常使用Ctrl+Z,毕竟谁也不能保证绝对不出错嘛。

不过,你有没有思考过计算机是怎么知道撤销哪一步操作呢?

其实很简单,计算机使用栈这种结构记录每一步操作,假如我们分别输入“曾经”,“沧海”,“难为水”,当我们输入完成后,发现“难为水”写成了“难为谁”(可能是输入法不够智能)。

当我们按下Ctrl+Z时,计算机只需要将撤销栈中栈顶数据对应的输入删除就可以实现撤销最近一次操作了。

逆波兰式

逆波兰式又称为后缀表达式,当然有后缀表达式就有前缀表达式(也称为波兰式),既然前后都有了,那也有中缀表达式。

假如我们有一道算术题:(1+3)×(4−2)(1+3) \times (4-2)(1+3)×(4−2)。

相信你可以很轻松的告诉我答案,但对于计算机来说,这太复杂了,既有括号,又有乘法,加法,优先级都搞不明白,还要怎么计算?不过也不是没有办法。

逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式形式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法、后序表示法。逆波兰记法不需要括号来标识操作符的优先级

逆波兰结构由弗里德里希·鲍尔(Friedrich L. Bauer)和艾兹格·迪科斯彻在1960年代早期提议用于表达式求值,以利用堆栈结构减少计算机内存访问。逆波兰记法和相应的算法由澳大利亚哲学家、计算机学家查尔斯·汉布尔(Charles Hamblin)在1960年代中期扩充。

在1960和1970年代,逆波兰记法广泛地被用于台式计算器,因此也在普通公众(如工程、商业和金融等领域)中使用。

以上来自维基百科逆波兰表示法词条,能够科学上网的小伙伴可以自行阅读。

所以上面的题目在逆波兰表达式中为:13+42−×1\enspace3 + 4\enspace2 -\times13+42−×。

你发现没有,在逆波兰式和栈结合后,计算机不需要在考虑括号对运算优先级的提升了,这样计算机就可以快速计算了。

简单描述逆波兰式的算法过程为,数字按顺序压入栈,遇到符号时弹出栈顶的两个数字进行计算

大概原理是这么简单,不过实际处理起来还是比较复杂的,这里附上我实现的简易版逆波兰式算法((没有中缀表达式的转换过程,没有处理任何边界情况)。

循环队列

使用数组实现队列时,出队不得不移动数据以保证下次依旧可以通过下标0取得数据,因此,出队操作的时间复杂度是O(n)O(n)O(n),显然是有点慢了。

如果我们换一个角度思考,为了保证下标0可持续使用,而移动数据代价是不是太大了?可不可以改变下标,而不移动数据呢?

答案是肯定的,我们可以不断改变队首的位置,而非移动数据来保证队首始终在下标为0的位置。

每次出队后指向队首的指针向后移动一位,入队后指向队尾的指针同样向后移动一位。这样,在不考虑超出数组容量的前提下,可以循环往复的使用数组中的内存,当然超过了就需要考虑扩容和重排队列数据了。

既然知道了基本原理,相信你可以很轻松的实现循环队列,提供我实现的循环队列作为参考,欢迎大家一起讨论。

结语

今天我们一起学习了栈和队列,它们是线性表中比较特殊的存在,如果要给线性表划分层级的话,基础的是数组和链表,在此之上我们可以构建出“更高级”的栈和队列。

在通过生活中的例子解释了栈和队列后我们学习了栈在计算机世界中丰富的应用,以及一种的队列–循环队列。

到今天为止线性表中比较基础的内容已经结束了,如果想要彻底的掌握它们还需要勤加练习。接下来,我们就要开始树的学习了,各位小伙伴们加油。

练习

  • 实现栈和队列
  • 实现循环队列
  • 剑指 Offer 06.从尾到头打印链表
  • 剑指 Offer 09.用两个栈实现队列
  • 剑指 Offer 50.第一个只出现一次的字符
  • 20.有效的括号
  • 933.最近的请求次数

本篇内容的代码仓库:Gitee代码仓库

因为各种敏感因素,成功访问GitHub就像抽奖,只好暂时放弃Github了。


好了,今天就到这里了,Bye~~

10.数据结构:栈和队列相关推荐

  1. 数据结构栈与队列的应用之汽车轮渡问题——自己的一些理解

    本题摘自王道数据结构栈与队列的应用的课后题,题目如下: 某汽车轮渡口,过江渡船每次能载10辆汽车过江.过江车辆分为客车类和货车类,上渡船有如下规定:同类车先到先上船,客车先于货车上船,且每上4辆客车, ...

  2. 数据结构——栈与队列相关题目

    数据结构--栈与队列相关题目 232. 用栈实现队列 思路 225. 用队列实现栈 1.两个队列实现栈 2.一个队列实现栈 20. 有效的括号 思路 1047. 删除字符串中的所有相邻重复项 思路 1 ...

  3. 数据结构栈和队列_使您的列表更上一层楼:链接列表和队列数据结构

    数据结构栈和队列 When you want to store several elements somewhere in a program, the go-to data type is an a ...

  4. 第十章 基本数据结构——栈和队列

    摘要 本章介绍了几种基本的数据结构,包括栈.队列.链表以及有根树,讨论了使用指针的简单数据结构来表示动态集合.本章的内容对于学过数据结构的人来说,没有什么难处,简单的总结一下. 1.栈和队列 栈和队列 ...

  5. 大话数据结构-栈与队列

    文章知识点来至于大话数据结构里边章节知识, 这篇主要介绍栈与队列在计算机中存储形式, 以及在某些算法领域中对栈和队列的相关应用.章节最后介绍了著名的逆波兰表达式, 以及通过算法来实现该表达式的运算过程 ...

  6. 数据结构——栈与队列操作(用栈模拟队列)

    [栈与队列操作] 问题描述:假设有两个长度相同的栈 S1,S2,已知以下入栈.出栈.判栈满和判栈空操作: void Push(S,x); Elemtype Pop(S); bool StackFull ...

  7. 基本数据结构 - 栈和队列

    摘要 本章介绍了几种基本的数据结构,包括栈.队列.链表以及有根树,讨论了使用指针的简单数据结构来表示动态集合.本章的内容对于学过数据结构的人来说,没有什么难处,简单的总结一下. 1.栈和队列 栈和队列 ...

  8. 数据结构栈和队列的实现

    数据结构的实验,栈和队列的实现. 栈的特点:先进后出,类似于一个只有一个口子,且一次只能容一个物体通过的容器,放在上面的物体必须先拿出才能拿下面的. 队列的特点:先进先出,类似于火车通过隧道,先进入隧 ...

  9. 数据结构——栈和队列

    目录 1.栈 1.1栈的基本概念 1.2栈的顺序存储实现 1.3共享栈 1.4栈的链式存储实现 1.5栈在括号匹配中的应用 1.6栈在表达式求值中的应用 1.6.1中.前.后缀表达式 1.6.2后缀表 ...

  10. 王道——数据结构——栈和队列(1)

    系列文章目录 其他章节相关文章 王道--数据结构--树与二叉树(1) 本章节其他相关文章 文章目录 系列文章目录 其他章节相关文章 本章节其他相关文章 前言 一.栈的顺序存储 一.顺序栈 二.共享栈 ...

最新文章

  1. python opencv单通道转多通道_13、OpenCV绘图和文本显示
  2. Python 数值计算库之-[Pandas](六)
  3. Hi3516A开发--根文件系统
  4. FreeRTOS队列
  5. 哪种语言 连接 oracle,Go语言连接Oracle(就我这个最全)
  6. 上海师范大学计算机技术考研分数线,上海师范大学2019年考研复试分数线已公布...
  7. oracle创建job权限
  8. OpenShift 4 - Knative教程 (3) 了解Knative Serving的核心对象
  9. 阿里巴巴Java开发手册--各个版本汇总
  10. 通过高德地图api获取地点坐标(以查询物资点为例)
  11. MATLAB分段三次 Hermite 插值
  12. 使用uCommand执行复杂的任务
  13. MarkdownPad的livepreview预览无效,显示this view has crashed
  14. shell脚本——一键完成虚拟机初始化
  15. 一次光纤线路故障导致的光纤猫信号灯异常用户无法上网的故障解决过程
  16. 中国专利整篇专利PDF格式下载
  17. matlab 中atan2函数的介绍
  18. Python 自然语言处理(基于SnowNLP)
  19. 【BZOJ3506】[CQOI2014] 排序机械臂(Splay)
  20. 20172327 2018-2019-1《程序设计与数据结构》课程总结

热门文章

  1. Unity3d静动态批处理Batching优化帧率、Batches(DrawCall) 初使用
  2. 都马上2020年了,还学什么PMP?
  3. 四年级上用计算机算的题,2019-2020年四年级数学上册11.1用计算器计算练习题及答案...
  4. 小学奥数思维训练题(十)
  5. bim 二次开发c语言,BIM百科 | Revit二次开发入门--创建一个简单的程序①
  6. 计算 ITPC 你需要知道这些……
  7. 【报错记录】OBS Studio 显示器捕获黑屏 Nvidia控制面板 “显示设置不可用 未连接GPU显示器”
  8. 2.2云计算架构概述
  9. CF1349A. Orac and LCM(策略 + 维护后缀gcd)
  10. arcgis地质灾害符号图例_ArcGIS软件操作系列二(地图制图)