1. 栈
- 栈是限定仅在表尾进行插入或删除的线性表
- 表尾称为栈顶,表头称为栈底
- 后进先出
- 栈既然是一种线性结构,就能够以数组或链表(单向链表、双向链表或循环链表)作为底层数据结构
- 操作
- 压栈:栈的插入操作,叫做进栈,也称压栈、入栈,通常命名为push
- 弹栈:栈的删除操作,也叫做出栈,通常命名为pop
- 求栈的大小
- 判断栈是否为空
- 获取栈顶元素的值
2. 栈的数组实现
- 以数组为底层数据结构时,通常以数组头为栈底,数组头到数组尾为栈顶的生长方向
- 代码
- Stack.h
1 | template<typename T> |
- Stack.cpp
1 | /*栈的判空操作*/ |
3. 栈的单链表实现
- 以链表为底层的数据结构时,以链表头为作为栈顶较为合适,这样方便节点的插入与删除
- 压栈产生的新节点将一直出现在链表的头部
- 代码实现
- Stack.h
1 | /*链表节点结构*/ |
- Stack.cpp
1 | /*返回栈的大小*/ |
4. 栈的代码题
4.1 数制转换
- 10进制转换为其他进制的数采用取余法,即每次将整数部分除以8,余数为该位权上的数,而商继续除以8,余数又为上一个位权上的数,这个步骤一直持续下去,直到商为0为止,最后读数时候,从最后一个余数起,一直到最前面的一个余数
- 代码
1 | void Conversion(int n) { |
4.2 括号匹配的检验
- 代码
1 |
|
4.3 汉诺塔问题
- 非递归算法
- 根据圆盘的数量确定柱子的排放顺序:
- 若n为偶数,按顺时针方向依次摆放 A B C
- 若n为奇数,按顺时针方向依次摆放 A C B
- 然后进行如下操作
- 按顺时针方向把圆盘1从现在的柱子移动到下一根柱子,即当n为偶数时,若圆盘1在柱子A,则把它移动到B;若圆盘1在柱子B,则把它移动到C;若圆盘1在柱子C,则把它移动到A
- 接着,把另外两根柱子上可以移动的圆盘移动到新的柱子上。即把非空柱子上的圆盘移动到空柱子上,当两根柱子都非空时,移动较小的圆盘
- 反复进行(1)(2)操作,最后就能按规定完成汉诺塔的移动。
- 根据圆盘的数量确定柱子的排放顺序:
1 |
|
- 递归算法
- 设Hanoi(n,a,c,b)表示n个圆盘在a柱上,通过服从汉诺塔规则的若干步骤移动,在b柱的辅助下,全部按原顺序移动到了c柱上
1 |
|
5. 队列
- 先进先出
- 允许插入的一端叫队尾,允许删除的一端叫队头
6. 队列题
6.1 用两个栈实现队列
- 用两个栈来实现一个队列,完成队列的 Push 和 Pop 操作
in 栈用来处理入栈(push)操作,out 栈用来处理出栈(pop)操作。一个元素进入 in 栈之后,出栈的顺序被反转。当元素要出栈时,需要先进入 out 栈,此时元素出栈顺序再一次被反转,因此出栈顺序就和最开始入栈顺序是相同的,先进入的元素先退出,这就是队列的顺序
- push 元素时,始终是进入栈,pop 和 peek 元素时始终是走出栈
- pop 和 peek 操作,如果出栈为空,则需要从入栈将所有元素移到出栈,也就是调换顺序,比如开始push的顺序是 3-2-1,1 是最先进入的元素,则到出栈的顺序是 1-2-3,那 pop 操作拿到的就是 1,满足了先进先出的特点
- pop 和 peek 操作,如果出栈不为空,则不需要从入栈中移到数据到出栈
代码
1 | void StackAsQueue(std::vector<int> data) { |