四 栈和队
4.1 栈
4.1.1 简介
栈是一种后进先出
的表结构;
栈在软件中的应用:word的撤销功能
栈的后进先出的思想在生活中的应用有:火车道岔;子弹夹
4.1.2 概念
A 定义
只允许在同一个端点处进行插入或删除的表结构称为栈(stack)
- 栈顶(top)
- 栈底(bottom)
- 进栈(push)
- 出栈(pop)
B 特点
后进先出表、LIFO表
栈结构,像开口向上的圆桶
结点像编了号的木块
C 作用
辅助存储机构:用来存储程序运行期间临时保存的信息。
D 分类
顺序栈
链式栈
4.1.3 顺序栈
A 定义
栈空指针-1,栈空间、数组
1 |
|
程序执行期间,将不定期的进栈、出栈
开始时,栈空,指针top的值等于EMPTY
进出栈算法需能够配合
B 顺序栈的进栈算法
1 | int push(int s[], int &top, int x) //进栈函数 |
C 顺序栈的出栈算法
1 | int pop(int s[], int &top, int &x) //退栈函数 |
D 性能分析
时间复杂性:T(n) = O(1)
1 | int push(int s[], int &top, int x) |
E 两个堆栈利用空间
1 | typedef strcut stack |
4.1.4 链式栈
链式栈实质就是在头指针处插入删除
A 链式栈入栈出栈算法
1 | int push(ptr &top, int x) |
4.1.5 栈的应用
A 栈在中断中作用
- 中断:一个程序执行期间,被其他程序所打断
- 断点:被打断的地方
- 现场:被打断的程序当前执行情况
保护现场和恢复现场
嵌套中断的现场需要蹭蹭保护,必须“后进先出”——栈
一个现场——栈架(stack frame)
B 简单算术表达式计算
算术表达式的组成:操作符、操作数、运算规则(算符优先级)
B.1 题目
B.2 规则
注:优先级必须高于顶符才能进栈,等于和小于,都是做出栈操作。
B.3 解答步骤(未设置栈底符号)
B.5 符号优先级比较
4.1.6 小结
- 栈是最常用的表结构
- 从根本上认识栈的基本原理和操作方法,对于认识程序的嵌套和递归调用,在程序设计中自觉地使用栈具有重要的意义
- 在应用方面,借助中缀表达式求值算法的原理,进一步理解栈在算法设计中的应用,是非常必要的。
4.2 队列
4.2.1 简介
队列是常用的数据结构,常用来辅助
先进先出
队列常采用循环队列的形式
生活中的例子:
- 排队打饭:站在队伍头的人先打饭走人,新来的站在队伍最后
4.2.2 概念
A 术语和图示
- 插入端,队尾(rear)
- 删除端,对头(front)
- first和last:分别指向队头元素和队尾元素
- 进队和出队
- 出队,首指针往后移
- 进队,尾指针往后移
B 特点
- 先进先出
- 需要考虑的因素
- 队头、队尾指针
- 队空队满
- 如何充分利用已出队元素所占存储单元等诸多因素
4.2.3 顺序队
顺序队的基本用法:收尾指针用法
A 用法[1],last指向实际队尾、first指向实际队头(麻烦)
B 用法[2],尾指针last前置
尾指针指向的是下一个元素要进的位置(尾是前移),不是当前队列实际最后一个元素。
C 用法[3],头指针first后置
头指针指向当前队列最前一个元素的后一位(头是后移)
D 判断队空
first = last=i(i是0~m-1之间的任一值)
E 判断队满
- 情况1:在程序执行期间,如果要求进队的元素总量不超过数组长度m,不会出现队满情况
- 情况2:在程序执行期间,需要进队处理的元素总量多于m个,但任何时刻,队中的元素数量始终小于m,仍可使用长度为m的数组存储(不会发生队满)
4.2.4 循环队(环形队,cyclic queue)
A 定义
特点:重复使用已退队元素所占存储单元!
注意,队尾指针和队头指针其实是对队列总数m取模操作。本质上物理存储还是一个数组。
B 举个栗子
以队尾指针前置环形队为例
1 | //元素x进队 |
C 队空队满状态
C.1 判断空
在队列王国里,大家判空都一样
first == last
C.2 判断满
开始时,队空,指针first=last=0
若一段时间捏,只进不出,last赶上first,满
若一段时间内,只出不进,first赶上last,空
当first等于last时,无所适从
解决方法:少用一个单元:
因此,常用的计算队列长度公式为:
(last - first + m) % m //m为表长
- 队空状态:
first = last
- 队满状态:
(last+1)%m == first
D 循环对进队出队程序
1 | // 循环对进队程序 |
4.2.5 链式队列
A 概念
链式队可采用单向加头链表结构
first为首指针,last为尾指针
- 进队:将新结点插在表尾处,last移向新结点
出队:将头结点后的第一个元素出队,删除头结点(头结点不固定)保证尾结点不被删除
判断空:first和last同时执行头结点。
first = last
B 进队算法
1 | // 进队算法 |
C 出队算法
1 | // 出队算法 |
4.2.6 小结
- 特点:先进先出
- 队列通常采用循环队列形式(以尾指针前置为例)
- 循环队列判空:
first == last
- 循环队列满:
(first+1)%m == last
- 循环队列判空:
参考文献
[1] 数据结构 – 中国人民解放军陆军工程大学 –陈卫卫、李清等 – 公开课 – 中国大学MOOC