一、什么是栈?
关于“栈”,有一个非常贴切的例子,就是往枪里面装子弹。装子弹的时候都是从前往后一个一个进;打枪发射子弹的时候,是后装的子弹先出,先进的子弹后出,子弹不能从中间任意出。后进者先出,先进者后出,这就是典型的“栈”结构。
栈相对数组和链表貌似只有限制没有任何优势。其实从功能上来说,数组或链表确实可以替代栈,但是存在即合理,每⼀种数据结构都是在特定的使⽤场景下的抽象,⽽且,数组或链表虽然操作上的确灵活⾃由,但使⽤时就⽐较不可控,⾃然也就更容易出错。当某个数据集合只涉及在⼀端插⼊和删除数据,并且满⾜后进先出、先进后出的特性,这时我们就应该⾸选“栈”这种数据结构。
二、栈的插入删除操作
栈的操作只允许在一端插入和删除数据,仅在表尾进行插入和删除操作,这一端被称为栈顶,另一端称为栈底,是一种“操作受限”的线性表。
push入栈:向一个栈插入新元素称为进栈(入栈或压栈)新元素放在栈顶元素上面,使 之成为新的栈顶元素; pop出栈:从一个栈删除元素称为出栈或退栈,是将栈顶元素删除掉。
⾸先取出近添加的数据的⽅法称为“后进先出”(Last In First Out)简称:LIFO
三、栈的实现
栈主要包含两个操作:入栈和出栈,也就是在栈顶插入一个数据和从栈顶删除一个数据。栈既可以用数组来实现,也可以用链表来实现。用数组实现的栈,我们叫作顺序栈,用链表实现的栈,我们叫作链式栈。
(在这里不写代码,只分析逻辑原理,代码可以在百度上获得)
1.顺序栈
- 顺序栈即就是顺序存储元素的,顺序栈可以通过数组来实现,将数组的首元素放在栈底,最后一个元素放在栈顶,之后指定一个 top 指针指向栈顶元素的位置。
- 当栈中只有一个元素时,此时 top=0 ,一般以 top 是否为 -1 来判定是否为空栈, 当定义了栈的最大容量时,则栈顶 top 必须小于最大容量值。
2.链表栈
关于链式栈,就是用链表的方式对栈的表示。通常,可以把栈顶放在单链表的头部。
由于链栈的先进后出,原来的头指针就显得毫无作用了。因此,对于链栈来说,是不需要头指针的。但是需要增加指向栈顶的 top 指针,这是进栈和出栈操作的重要支持。
对于链表我们添加都是在其后追加,但是对于链栈,添加数据的压栈操作需要额外处理,插入新的数据放在头部,则新的结点放置在原栈顶,再让 top 指针指向新的结点。
在链式栈中进行删除操作时,只能在栈顶进行操作。因此,将栈顶的 top 指针指向栈顶元素的 next 指针即可完成删除。
四、栈的应⽤场景
- 表达式的转换:中缀转后缀与求值 ;中缀转前缀与求职
- 递归⽅式就是函数⾃身调⽤⾃身,当递归每次调⽤⾃身时,可以看作是⼊栈的过程,当递归条件满⾜后,结束时递归再⼀级⼀级的返回,返回过程可以看作是出栈的过程。递归和栈的实现过程可以看出都是符合“先进后出,后⼊先出”的原则,所以递归⽅式其实可以转化为栈的⽅式来实现。
- 对于⼆叉树的遍历,先序、中序、后序遍历都可以⽤到递归⽅法实现,既然递归可以转化为栈,那么也可以把对⼆叉树的遍历改为⽤栈的思想来实现