系列文章目录
文章目录
堆栈
堆栈的定义和基本操作
定义
堆栈(简称栈)是插入和删除只能在其同一端进行的线性表,并按后进先出的原则进行操作
栈顶:允许进行插入、删除操作的一段,又称表尾。用栈顶指针(top)来指示栈顶元素
栈底:固定端,又称表头
空栈:表中没有元素
性质
- 后进先出性:可以对输入序列部分或全局求逆;凡符合后进先出性,都可以应用栈,如十进制数与其他数制的转换、递归的实现、算术表达式求值等问题。堆栈也称后进先出(Last In First Out)表,简称LIFO表
- 封闭性:插入和删除只能在栈顶进行,除了栈顶元素外,其他元素不会被改变。因而,栈的封闭性很好,使用起来很安全
基本操作
- 初始化
- push(item):压入一个元素(插入)
- pop(item):弹出一个元素(删除)
- peek(item):取出栈顶元素值
- IsEmpty():判断栈空
- IsFull():判断栈满
- clean():置空栈
顺序栈
定义
- 用顺序存储方式实现的堆栈称为顺序栈
- 顺序方式:使用数组存储
- 存储要求:栈的规模必须小于或等于数组的规模,当栈的规模等于数组的规模时,就不能再向栈中插入元素
示例:
存放堆栈元素的数组:
T stackArray[MaxStackSize]
栈顶所在数组元素的下标:int top
堆栈空: top = -1
堆栈满: top = MaxStackSize - 1
入栈算法
- 判断栈是否满
- top = top + 1
- A[top] = item
出栈算法
- 判断栈是否空
- item = A[top]
- top = top + 1
存取栈顶元素算法
- 判断栈是否空
- item = A[top]
综述
- 堆栈是一种操作受限制的线性表
- push和pop操作只与栈顶有关
- 堆栈的特性:后进先出
- 堆栈状态
- 栈空:top = -1
- 栈满:top = MaxStackSize - 1
- 使用数组实现顺序栈效率很高,但若同时使用多个栈,顺序栈将浪费大量空间
链式栈
定义
栈的链式存储方式称为链栈
链栈是运算受限制的单链表。其插入和删除操作只能在表头位置进行。因此,链栈没有必要像单链表那样附加头节点,栈顶指针top就是链表的头指针
链式表中不需要哨位结点
入栈算法
- 创建结点s(申请空间)
- item = data(s) next(s) = top
- top = s
出栈算法
- 判断栈是否空
- item = data(top)
- q = next(top)
- 释放top结点空间
- top = q
存取栈顶元素
- 判断栈是否空
- item = data(top)
清空栈
- 如果栈不空,循环2,3,4
- q = next(top)
- 释放top结点空间
- top = q
顺序栈与链式栈比较
- 空间复杂性
- 顺序栈有空间浪费
- 链式栈所需空间是根据需要随时申请,其代价是为每个元素提供空间以存储其next指针域
- 时间复杂性
- 栈顶的基本操作(压入、弹出和栈顶元素存取),顺序栈和链式栈的时间复杂性均为O(1)
- 非栈顶元素的基本操作,顺序栈时间复杂性为O(1),链式栈为O(n)
堆栈的应用
括号匹配
- 高级语言程序设计中的各种括号应该匹配,开括号与相应的闭括号匹配
- “(” 与 “)”匹配
- “[”与 “]” 匹配
- “{”与 “}” 匹配
- 示例:字符串{a=(b*c}+free( ) ]中的括号就没有匹配上,因为串中第一个闭括号 “}” 和最近的未匹配开括号 “(” 不匹配
- 检查输入文本文件中的括号是否正确匹配,文件中的字符是按次序依次输入的
- 如果输入的字符是开括号,应该将其存放起来,继续下一个字符的输入
- 如果输入的是闭括号,应考察其与最近的未匹配开括号是否匹配,若匹配,则应将匹配的开括号从存放处删除
- 每次用来和闭括号进行匹配的开括号都是最后输入的,这符合堆栈的后进先出策略,因此用堆栈来存放开括号是合理的
十进制数转换为r进制数
- 十进制数转换为r进制数
- 十进制整数 x 除以基数 r,所得整余数是 r 进制数 y 的最低位 y0,压入堆栈
- 用 x除以 r 的整数商除以 r,所得整余数是 y 的次低位 y1,压入堆栈,依此类推
- 直到商为 0 ,所得整余数是 y 的最高位ym,压入堆栈;此时,栈中的 m+1 个 r 进制数即为所得
算数表达式求值
- 算术表达式求值是程序设计语言编译中的一个最基本问题。它的实现方法是栈的一个典型的应用实例
- 表达式都是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的
- 其中操作数可以是常数,也可以是变量或常量的标识符;运算符是算术运算符( + , - , * , / );界限符为左右括号和标识表达式结束的结束符
中缀表达式——运算符在操作数之间
如: A * B / C
运算规则:
- 先计算括号内,后计算括号外
- 在无括号或同层括号内,先进行乘除运算,后进行加减运算,即乘除运算的优先级高于加减运算的优先级
- 同一优先级运算,从左向右依次进行
- 用计算机来处理中缀表达式比较复杂。一个中缀表达式中有多少个运算符,原则上就得对表达式扫描多少遍,才能完成计算
- 在编译系统中,把中缀表达式转换成另外一种表示方法,即后缀表达式,然后对后缀表达式进行处理,后缀表达式也称为逆波兰式
后缀表达式
1929 年,由波兰逻辑学家(Lukasiewicz)提出。
[例] A * B / C;
A B * C / ;
- 定义:运算符紧跟在两个操作数之后的表达式称为后缀表达式
- 优点
- 后缀表达式没有括号
- 不存在优先级的差别
- 计算过程完全按照运算符出现的先后次序进行
中缀表达式转换成后缀表达式
- 首先设定一个运算符栈,用来保存扫描中缀表达式得到的暂不能放入后缀表达式中的运算符
- 基本思想:从左到右依次读出中缀表达式中的各个符号(操作数或运算符),每读出一个符号后,根据如下运算规则进行处理:
- 假如是操作数,将其放入后缀表达式中
- 如果是运算符
- 栈空:运算符放入栈中
- 栈不空:比较当前读到的运算符与栈顶运算符的优先级
- 假如读出的运算符的优先级大于栈顶运算符的优先级,则将其压入运算符栈,读中缀表达式的下一个符号
- 若栈顶运算符的优先级比读到的运算符的优先级高或二者相等,弹出栈顶运算符放入后缀表达式中,返回(2)继续比较
- 遇到“(”,压入堆栈
- 遇到“)”,把“(”上面的操作符依次弹出加到后缀表达式中,“(”出栈
- 假如读出的是表达式结束符“#”,栈中剩余的运算符依次出栈并写入到后缀表达式中,转换完成
后缀表达式计算
- 从左到右读入后缀表达式,若读到的是操作数,将它压入堆栈
- 若读到的是运算符,就从堆栈中连续弹出两个元素(操作数),进行相应的运算,并将结果压入栈中
- 读入结束符时,栈顶元素就是计算结果。
拓展
- 递归
- 双栈:两个底部相连的栈
- 超栈:一种插入首先的双端栈,插入操作限制在一段,而删除操作允许在两端
多栈共享邻接空间
在计算机系统软件中,各种高级语言的编译系统都离不开栈的使用。常常一个程序中要用到多个栈,为了不发生上溢错误,就必须给每个栈预先分配一个足够大的存储空间,但实际中很难准确地估计。另一面方面,若每个栈都预分配过大的存储空间,势必会造成系统空间紧张。若让多个栈共用一个足够大的连续存储空间,则可利用栈的动态特性使它们的存储空间互补。这就是栈的共享邻接空间
双向栈
栈的共享中最常见的是栈的共享。假设两个栈共享一维数组stack[MAXNUM],则可以利用栈的“栈底位置不变,栈顶位置动态变化”的特性,两个栈底分别为-1和MAXNUM, 而它们的栈顶都往中间方向延伸。因此,只要整个数组stack[MAXNUM]未被占满,无论哪个栈的入栈都不会发生上溢。
队列
队列的定义和基本操作
定义
队列是一种操作受限制的线性表。是一种先进先出(First In First Out,简称FIFO)的线性表。只允许在表的一端进行插入,而在另一端进行删除
队首:允许进行删除的一端称为队首
队尾:允许进行插入的一端称为队尾
没有元素的队列称为空队列
性质
- 先进先出性:可以对输入序列起缓冲作用;凡符合先进先出性,都可以应用队列,如果操作系统中作业调度、图的广度优先搜索等问题
- 封闭性:与栈类似,队列的封闭性也很好,使用起来很安全
基本操作
- 队列初始化
- 向队尾添加元素(入队)
- 删除队首元素(出队)
- 获取队首元素(存取)
- 判断队列是否为空
- 确定队列元素个数
- 置空队列
顺序队列
用顺序存储方式存储的队列被称为顺序队列。
- 存放队列元素的数组
- T qlist[MaxQSize]
- front 队首元素的数组下标
- rear(要入队元素的下标)队尾元素的下标+1
- 插入:rear = rear+1
- 删除队首元素的方法1:令front = front + 1
- 出现问题,空间利用差
- 删除队首方元素法2:元素向前移动,front总是等于0
- 删除队首元素方法3 :循环队列
- 删除时front往前移动一位
- 插入元素时:rear顺时针移动一位
链式队列
限制仅在表头进6行删除操作和表尾进行插入操作的单链表
结构:
插入操作
- s ← new() data(s)← item next(s)← NULL
- 判断队列是否为空
- 若为空 front ← s
- 非空 next(rear)← s
- rear ← s
删除操作
- 判断队列是否为空
- 不为空, q ← front ,item ←data(q)
- front ← next(front)
- delete q
- 判断出队后是否为空
- 若为空 rear ← NULL