线性表之栈和队列
操作受限的线性表
线性表的子集之栈和队列
栈:后进先出的线性表,表尾插入(n+1)表尾删除(n)。
队列:先进先出的线性表,表尾插入(n+1)表头删除(1),用于类似排队问题。
栈和队列的定义和特点
栈的定义和特点
定义:
逻辑结构:与线性表相同,一对一。
存储结构:顺序栈或链栈,顺序栈更常见。
运算规则:只能在栈顶运算,依照后进先出规则LIFO访问节点。last in first out
实现方式:关键是编写入栈和出栈函数。
队列的定义和特点
定义:
逻辑结构:与线性表相同,一对一。
存储结构:顺序队或链队。
运算规则:只能在队首和队尾运算,依照先进先出规则FIFO访问节点。first in first out
实现方式:关键是编写入队和出队函数。
典型案例
栈
1.进制转换
除以进制数,用栈存储取余结果,然后出栈即得到转换的进制数。(顺序刚好反过来)
2.括号匹配的检验
括号依次进栈,遇到匹配的另一边括号则出栈,遇到另一边但是不匹配则错误,或者最后只剩左(右)括号。
3.表达式求值
算符优先算法:
如果运算符比OPTR栈顶运算符优先级低,则说明栈顶运算符可以优先计算了。
队列
4.舞伴问题
先入队的男士或女士先出队配成舞伴。
顺序栈的表示和操作
栈的抽象数据类型
顺序栈的表示
两个指向同一数组的指针相减,表示所指的两个元素之间的元素个数
使用数组(顺序表)作为顺序栈存储方式的特点:
简单方便,但是易产生溢出。
上溢:栈满,又要压入元素,是一种错误。
下溢:栈已空,又要弹出元素,是一种结束条件。
顺序栈的操作实现
1.顺序栈的初始化
新建数组,用base指向数组即可。
2.判断顺序栈是否为空
3.求顺序栈的长度
4.清空顺序栈
只改变指针,实际上元素并没有被清除,但无影响,因为栈中元素表示的是top指针与base指针之间的元素,也只在这两者之间进行操作。出栈时也一样。
5.销毁顺序栈
6.顺序栈的入栈
6.顺序栈的出栈
链栈的表示和操作
链栈的表示
链栈是运算受限的单链表,链表中指针方向与一般的单链表不同,只能在链表头部进行操作。
链栈的操作实现
1.链栈的初始化
2.链栈是否为空
3.链栈的入栈
4.链栈的出栈
5.取栈顶元素
栈与递归
递归定义
若对象部分包含自己,或者自己给自己定义,则称这个对象是递归的。
若一个过程直接或间接地调用自己,则称这个过程是递归的。
递归应用三种情况
常用到递归方法的三种情况:
1.递归定义的数学函数
阶乘函数、2阶Fibonaci函数
2.具有递归特性的数据结构
二叉树(每个结点往下都是二叉树)、广义表 A=(a,A)
3.可递归求解的问题
迷宫问题、Hanoi塔问题
分治法
用分治法求解递归问题。
递归工作栈
嵌套调用函数,后调用的函数先返回,与栈的后进先出思想相同。
在函数递归调用的过程中,要用到“递归工作栈”。
递归工作栈是递归程序运行期间使用的数据存储区。
递归工作栈中记录着实参、局部变量、返回地址等工作记录。
递归的优缺点
优点:结构清晰,程序易读。不过一般都用递归就行,除非很注重时间效率。
缺点:每次调用都要生成工作记录,需要入栈出栈,时间开销大。
递归—>非递归
方法1:尾递归、单向递归–转换成->循环结构
尾递归类似求阶乘,单项递归类似2阶Fibonaci函数。
方法2:自用栈模拟系统的运行时栈
队列的表示和操作
队列的存储结构为链队或顺序队(循环顺序队)。
队列的抽象数据类型
顺序队列的表示
1.队列的顺序表示:
与栈不同的是:
栈为两个指针,队列是两个数组下标。
栈中直接用首指针在初始化时指向数组,而队列需要再定义一个指针来指向数组。
2.存在的溢出问题:
解决假上溢的方法——引入循环队列
利用模运算,求余数(mod或%)。
就是在移动下标指针时,不是+1,而是都取余数为新的位置(在不超过的时候与+1相同,只是超过可从头插入)。
3.循环队列的队空队满问题——
[1].另外设一个标志以区别队空队满
[2].另设一个变量,记录元素个数
[3].少用一个元素空间(即当rear+1==front的时候就判定为队满了,不继续插入了,继续插入两者相同就带来疑惑了。由于是循环队列,从而用取余法来判定)
循环队列的操作实现
1.循环队列的类型定义
2.队列的初始化
3.求队列的长度
4.循环队列的入队
5.循环队列的出队
6.取队头元素
链队列的表示与操作
若用户无法估计所用队列的长度,则宜采用链队列。
1.链队列的类型定义
链表的类型定义中,因为只有一个指针,所以结点指针就可表示链表。
但是链队列有两个指针,两者一起才构成链队列的类型结构。在定义指针时还是用结点数据类型来定义。
与链栈不同的是:链栈无头结点,并且只有头指针。
2.链队列运算指针变化状况
3.链队列的初始化
4.链队列的销毁
5.链队列的入队操作
6.链队列的出队操作
7.求链队列的队头元素