1、栈的定义
栈是限定仅在表尾进行插入和删除操作的线性表。我们把插入和删除的一段称为栈顶,另一端称为栈底,不含任何元素的栈称为空栈。由于栈本身是一个线性表,因此栈的存储方式也有两种,分别是顺序存储和链式存储。
1.1 栈的顺序存储结构
既然栈是线性表的特列,那么栈的顺序存储其实也是线性表顺序存储的简化。我们称为顺序栈。
(1)两栈的共享空间
因为顺序栈只准栈顶进出元素,因此不存在线性表插入和删除时需要移动元素的问题。不过顺序栈有很大缺陷,就是需要事先确定数组存储空间的大小。当我们有两个相同的栈,有可能第一个栈已经满了,再进栈就会溢出,而另一个栈还有很多存储空间空闲,此时我们可以通过共享空间的方式来节省存储空间。
此时,当栈1为空时,top1等于-1,当top2等于n时,此时栈2为空。若栈2时空栈,栈1 top1等于n-1时,栈1就满了。如果栈1为空栈,top2等于0时,栈2满。
1.2 栈的链式存储结构
链栈的存储结构如图所示,栈顶放在单链表的头部。因为有了栈顶在头部,单链表就不需要头结点了。对于链栈来说基本不会存在空间被占满的问题。
2、栈的作用
栈在程序设计中很重要的一个应用:在程序设计语言中实现了递归。什么时递归,可以去了解一下斐波那契数列。
2.1 递归
递归的定义:把一个直接调用自己或通过一系列的调用语句间接地调用自己的函数,称为递归函数。每个递归定义都必须至少有一个条件,满足时递归不再进行,即不再引用自身而是返回值退出。
2、队列的定义
队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。队列是一种先入先出的线性表,简称FIFO。运行插入的叫队尾,运行删除的叫队头。
(1)所谓的入队操作,其实就是在队尾追加一个元素,而不需要移动任何元素,因此它的时间复杂度为O(1)。
(2)与栈不同的是,队列元素出队是在队头,即下标为0处,那就意味着所有元素都需要向前移动,以保证队列的对头不为空,此时时间复杂度为O(n)。
2.1、循环队列
我们把头尾相接的顺序存储结构的队列称为循环队列。循环队列可以解决队列出队性能差的问题。
循环队列引入两个指针,front指向头元素,rear指向队尾元素的下一个位置。当rear等于front时则队列为空。假设长度为5的数组,初始状态front与rear指针均是下标为0的位置,入队a1、a2、a3、a4后如图所示:
出队a1、a2,则front指针指向下标为2的位置,rear不变。此时再入队a5则会造成数组越界错误,但队列中还有空闲的空间,此现象称为*“假溢出”*。
如何解决“假溢出”的现象?
解决的方法只需要将溢出的元素再从头开始,头尾相接。当入队a6时,将它放在下标为0处。rear指针指向下表为1处,当rear和front指针重合时则队列满了。
3、思考题
1、现实应用中哪些场景用到队列和栈这两种数据结构
2、循环队列队列满了和空时,都是rear==front,如何区分呢?