清华大学数据结构.ppt_第1页
清华大学数据结构.ppt_第2页
清华大学数据结构.ppt_第3页
清华大学数据结构.ppt_第4页
清华大学数据结构.ppt_第5页
已阅读5页,还剩78页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1 第三章栈与队列 1 数据结构电子教案 殷人昆王宏 2 栈队列栈的应用 表达式求值栈的应用 递归队列的应用 打印杨辉三角形优先级队列 第三章栈与队列 3 只允许在表的一端进行插入和删除的线性表 考虑指针个数和栈空 栈满表示允许插入和删除的一端称为栈顶 top 另一端称为栈底 bottom 特点后进先出 LIFO LastInFirstOut 栈 Stack 退栈 进栈 a0 an 1 an 2 top bottom 4 定义 ADT 栈 Stack 特殊的线性表插入 删除操作只能在一端进行 另一端禁止严格说 查找操作也是如此Push Pop getTop 特点后进先出 LIFO儿童玩具手枪的子弹夹 铁路调度编组站都是栈在实际生活中的应用原型 Push Pop 5 templateclassStack 栈的类定义public Stack 构造函数virtualvoidPush Tx 0 进栈virtualboolPop T 判栈满 教材中尚包括getsize 取栈中元素个数 栈的抽象数据类型 6 include include include stack h templateclassSeqStack publicStack 顺序栈类定义private 栈的数组存储表示 顺序栈 7 T elements 栈元素存放数组inttop 栈顶指针intmaxSize 栈最大容量voidoverflowProcess 栈的溢出处理 顺序栈必备public SeqStack intsz 50 构造函数 建立空栈 SeqStack delete elements 析构函数voidPush Tx 进栈boolPop T 8 顺序栈的构造函数 templateSeqStack SeqStack intsz top 1 maxSize sz 建立一个最大尺寸为sz的空栈 若分配不成功则错误处理elements newT maxSize 创建栈的数组空间assert elements NULL 动态分配是否成功 断言 assert 机制 若断言语句assert参数表中给定的条件满足 则继续执行后续的语句 否则将调用stdlib h中的函数abort 打印出错行号和文件名 出错处理 终止程序的执行 9 top 空栈 top top top top top a进栈 b进栈 a a b a b c d e e进栈 a b c d e f进栈溢出 a b d e e退栈 c 10 top c退栈 b退栈 a b a a退栈 空栈 top a b d d退栈 c top a b c top top 进栈时先修改指针 然后元素进栈 退栈时先退栈顶元素再修改指针 11 顺序栈的操作 templatevoidSeqStack overflowProcess 私有函数 当栈满则执行扩充栈存储空间处理T newArray newT 2 maxSize 创建更大的存储数组 创建成功检查省略for inti 0 i top i newArray i elements i maxSize maxSize delete elements elements newArray 改变elements指针 12 templatevoidSeqStack Push Tx 若栈不满 则将元素x插入该栈栈顶 否则溢出处理if IsFull true overflowProcess 栈满elements top x 栈顶指针先加1 再进栈 templateboolSeqStack Pop T 13 templateboolSeqstack getTop T一个栈利用一片连续空间难免造成浪费解决办法 双栈共享一个栈空间 14 双栈共享一个栈空间 b 0 t 0 t 1 b 1 0maxSize 1 V 两个栈共享一个数组空间V maxSize 设立栈顶指针数组和栈底指针数组 考虑仅用栈顶指针可否t i 和b i 分别指示第i个栈 i 0 1 的栈顶与栈底初始t 0 b 0 1 t 1 b 1 maxSize栈满条件 t 0 1 t 1 栈顶指针相遇栈空条件 t 0 b 0 或t 1 b 1 退到栈底 15 boolPush DualStack 多个栈共享栈空间时用顺序表示处理相对复杂 16 栈的链接存储表示 链式栈 链式栈忽略栈满问题 空间可扩充插入与删除仅在栈顶处执行链式栈的栈顶在链首适合于多栈操作 top 17 链式栈 LinkedStack 类的定义 include 具体实现时的一种头文件形式 include include stack h usingnamespacestd templatestructStackNode 栈结点类定义Tdata 栈结点数据StackNode link 结点链指针StackNode Td 0 StackNode next NULL data d link next 构造函数 VC6 0库文件有iostream h 编译可以通过 但是VS2005和VS2008没有这个库文件 只能用标准命名空间 includeusingnamespacestd 18 templateclassLinkedStack publicStack 链式栈类定义private StackNode top 栈顶指针staticvoidoutput ostream 退栈 19 boolgetTop T 20 链式栈类操作的实现 templateLinkedStack makeEmpty 逐次删去链式栈中的元素直至栈顶指针为空 StackNode p while top NULL 逐个结点释放 p top top top link deletep templatevoidLinkedStack Push Tx 将元素值x插入到链式栈的栈顶 即链头 top newStackNode x top 创建含x新结点assert top NULL 创建失败退出 21 templateboolLinkedStack Pop T 链式栈在退栈时有栈空判断 Pop操作完成结果有不同的返回形式 但链式栈在进栈时不判断栈满 Push函数为无值类型 22 templatevoidLinkedStack output ostream 23 templateboolLinkedStack getTop T问题 当进栈元素的编号为1 2 n时 可能的出栈序列有多少种 关于栈的进一步讨论 24 设进栈元素数为n 可能出栈序列数为mn n 0 m0 1 出栈序列 n 1 m1 1 出栈序列 1 n 2 m2 2 m0 m1 m1 m0出栈序列中1在第1位 1进1出2进2出 出栈序列为 1 2 m0 m1 1出栈序列中1在第2位 1进2进2出1出 出栈序列为 2 1 m1 m0 1n 3 m3 5 m0 m2 m1 m1 m2 m0出栈序列中1在第1位 后面2个元素有m2 2个出栈序列 1 2 3 1 3 2 25 m0 m2 2出栈序列中1在第2位 1前有2后有3 出栈序列为 2 1 3 m1 m1 1出栈序列中1在第3位 前面2个元素有m2 2个出栈序列 2 3 1 3 2 1 m2 m0 2n 4 m4 14 m0 m3 m1 m2 m2 m1 m3 m0出栈序列中1在第1位 后面3个元素有m3 5个出栈序列 1 2 3 4 1 2 4 3 1 3 2 4 1 3 4 2 1 4 3 2 26 m0 m3 5出栈序列中1在第2位 前面有2 后面3 4有m2 2个出栈序列 2 1 3 4 2 1 4 3 m1 m2 2出栈序列中1在第3位 前面2 3有m2 2个出栈序列 后面有4 2 3 1 4 3 2 1 4 m2 m1 2出栈序列中1在第4位 前面3个元素有m3 5个出栈序列 2 3 4 1 2 4 3 1 3 2 4 1 3 4 2 1 4 3 2 1 m3 m0 5 27 一般地 设有n个元素按序号1 2 n进栈 轮流让1在出栈序列的第1 第2 第n位 则可能的出栈序列数为 推导结果为 28 栈混洗 另一种说法 Stackpermutationn个对象 a1 a2 an 依次进栈 并可以在任意可能的时刻出栈按照其出栈次序得到的每一序列 ak1 ak2 akn 称为一种混洗e g 1 2 3 4 4 3 2 1 3 2 4 1 1 2 3 4 29 栈混洗 可能的混洗总数SP n 观察SP n n 定理 SP n Catalan n 2n n 1 n SP 3 5SP 6 132证明 一些经典的数学问题最后都可归结为该问题的求解n个结点不同形态二叉树的数目n个元素的集合上的等价关系的数目n 1个矩阵相乘的不同方法数 30 栈混洗 若输入序列 1 2 3 n 对于任一排列 p1 p2 p3 pn 如何判定它是否一种栈混洗 简单的情况 1 2 3 n 3栈混洗共有 6 4 3 5种全排列共有 3 6种少的那个排列是 312 为什么是它 充要性 Knuth 1968 Apermutationisastackpermutationiffitdoesnotinvolvethepermutation312 利用一个堆栈从12 n得到排列p1p2 pn 当且仅当 不存在下标i j k使得pj pk pi 31 栈的应用 表达式求值 一个表达式由操作数 亦称运算对象 操作符 亦称运算符 和分界符组成 算术表达式有三种表示 中缀 infix 表示 如A B 前缀 prefix 表示 如 AB 后缀 postfix 表示 如AB 32 中缀表达式a b c d e f后缀表达式abcd ef 前缀表达式 a b cd ef表达式中相邻两个操作符的计算次序为 优先级高的先计算 优先级相同的自左向右计算 当使用括号时从最内层括号开始计算 表达式举例 33 应用后缀表示计算表达式的值 从左向右顺序地扫描表达式 并用一个栈暂存扫描到的操作数或计算结果 读到运算符则计算在后缀表达式的计算顺序中已隐含了加括号的优先次序 括号在后缀表达式中不出现 计算例abcd ef rst1 rst2 rst3 rst4 rst5 34 一般表达式的操作符有4种类型 算术操作符如双目操作符 和 以及单目操作符 关系操作符包括 这些操作符主要用于比较 逻辑操作符如与 或 非 括号 和 它们的作用是改变运算顺序 35 中缀表示 转后缀表示 先对中缀表达式按运算优先次序加上括号 再把操作符后移到右括号的后面并以就近移动为原则 最后将所有括号消去 如中缀表示 A B D E F A D C 其转换为后缀表达式的过程如下 36 中缀表示 转前缀表示 先对中缀表达式按运算优先次序通统加上括号 再把操作符前移到左括号前并以就近移动为原则 最后将所有括号消去 如中缀表示 A B D E F A D C 其转换为前缀表达式的过程如下 37 利用栈将中缀表示转换为后缀表示 使用栈可将表达式的中缀表示转换成它的前缀表示和后缀表示 为了实现这种转换 需要考虑各操作符的优先级 一元运算优先于二元运算算术运算优先于关系运算关系运算优先于逻辑运算 优先级操作符1单目 2 3 4 5 6 7 38 各个算术操作符的优先级 isp叫做栈内 instackpriority 优先数icp叫做栈外 incomingpriority 优先数 操作符优先数相等的情况只出现在括号配对或栈底的 号与输入流最后的 号配对时 39 中缀表达式转换为后缀表达式的算法 操作符栈初始化 将结束符 进栈 然后读入中缀表达式字符流的首字符ch 重复执行以下步骤 直到ch 同时栈顶的操作符也是 停止循环 若ch是操作数直接输出 读入下一个字符ch 若ch是操作符 判断ch的优先级icp和位于栈顶的操作符op的优先级isp 40 若icp ch isp op 令ch进栈 读入下一个字符ch 若icp ch isp op 退栈并输出 若icp ch isp op 退栈但不输出 若退出的是 号读入下一个字符ch 算法结束 输出序列即为所需的后缀表达式 41 42 43 应用中缀表示计算表达式的值 使用两个栈 操作符栈OPTR operator 操作数栈OPND operand 为了实现这种计算 需要考虑各操作符的优先级 44 各个算术操作符的优先级 isp叫做栈内 instackpriority 优先数icp叫做栈外 incomingpriority 优先数 操作符优先数相等的情况只出现在括号配对或栈底的 号与输入流最后的 号配对时 45 中缀算术表达式求值 对中缀表达式求值的一般规则 建立并初始化OPTR栈和OPND栈 然后在OPTR栈中压入一个 扫描中缀表达式 取一字符送入ch 当ch 并且OPTR栈的栈顶 时 结束算法 在OPND栈的栈顶得到运算结果 否则执行以下工作 若ch是操作数 进OPND栈 从中缀表达式取下一字符送入ch 46 若ch是操作符 比较icp ch 的优先级和isp OPTR 的优先级 若icp ch isp OPTR 则ch进OPTR栈 从中缀表达式取下一字符送入ch 若icp ch isp OPTR 则从OPND栈退出a2和a1 从OPTR栈退出 形成运算指令 a1 a2 结果进OPND栈 若icp ch isp OPTR 且ch 则从OPTR栈退出 对消括号 然后从中缀表达式取下一字符送入ch 47 voidInFixRun stackOPTR OPND 操作符栈OPTR操作数栈OPNDcharch op OPTR makeEmpty OPND makeEmpty OPTR Push 两个栈初始化 操作符栈进栈底标志getchar ch 读入一个字符op while ch op if isdigit ch 是操作数 进栈 OPND Push ch getchar ch else 是操作符 比较优先级OPTR getTop op 读一个操作符 48 if icp ch isp op 栈顶优先级低 OPTR Push ch getchar ch elseif icp ch isp op 栈顶优先级高OPTR Pop op OPND DoOperator op 从OPND退出两操作数运算 结果进OPND栈elseif ch 优先级相等且ch OPTR Pop op getchar ch 对消括号 OPTR getTop op 取出操作符栈栈顶元素准备下一轮比较 endofwhile OPND Pop ch cout ch endl 输出OPND栈顶结果 49 50 51 52 栈的应用 递归 递归的定义若一个对象部分地包含它自己 或用它自己给自己定义 则称这个对象是递归的 若一个过程直接地或间接地调用自己 则称这个过程是递归的过程 以下三种情况常常用到递归方法 定义是递归的数据结构是递归的问题的解法是递归的 53 定义是递归的 求解阶乘函数的递归算法longfactorial longn if n 0 return1 elsereturnn factorial n 1 例如 阶乘函数 54 求解阶乘n 的过程 主程序main fact 4 参数4计算4 fact 3 返回24 参数3计算3 fact 2 返回6 参数2计算2 fact 1 返回2 参数1计算1 fact 0 返回1 参数0直接定值 1返回1 参数传递 结果返回 递归调用 回归求值 55 例如 单链表结构一个结点 它的指针域为NULL 是一个单链表 一个结点 它的指针域指向单链表 仍是一个单链表 数据结构是递归的 56 搜索链表最后一个结点并打印其数值templatevoidPrint LinkNode f if f link NULL coutdatalink 57 在链表中寻找等于给定值的结点并打印其数值templatevoidPrint LinkNode f Tvalue if f NULL if f data value coutdatalink value 58 问题的解法是递归的 例 汉诺塔 TowerofHanoi 问题的解法 如果n 1 则将这一个盘子直接从A柱移到C柱上 否则 执行以下三步 用C柱做过渡 将A柱上的 n 1 个盘子移到B柱上 Hanoi n 1 A C B 将A柱上最后一个盘子直接移到C柱上 用A柱做过渡 将B柱上的 n 1 个盘子移到C柱上 Hanoi n 1 B A C 59 60 includevoidHanoi intn charA charB charC 解决汉诺塔问题的算法if n 1 cout move A to C endl else Hanoi n 1 A C B cout move A to C endl Hanoi n 1 B A C 61 3 A B C 2 A C B A C A B C 1 A B C A B C A C A C 1 C A B A B C A C A B A C C B A C 2 B A C A B C 1 B C A A B C A C A C 1 A B C A B C A C B C B A A C 62 自顶向下 逐步分解的策略 子问题应与原问题做同样的事情 且更为简单 解决递归问题的策略是把一个规模比较大的问题分解为一个或若干规模比较小的问题 分别对这些比较小的问题求解 再综合它们的结果 从而得到原问题的解 分而治之策略 分治法 这些比较小的问题的求解方法与原来问题的求解方法一样 63 构成递归的条件 不能无限制地调用本身 必须有一个出口 化简为非递归状况直接处理 Procedure if 递归结束条件return initialvalue else 递归return parameterchange 64 递归过程在实现时 需要自己调用自己 层层向下递归 退出时的次序正好相反 递归调用n n 1 n 2 1 0 1返回次序主程序第一次调用递归过程为外部调用 递归过程每次递归调用自己为内部调用 它们返回调用它的过程的地址不同 递归过程与递归工作栈 65 longFactorial longn inttemp if n 0 return1 elsetemp n Factorial n 1 returntemp voidmain intn n Factorial 4 RetLoc1 RetLoc2 66 递归工作栈 每一次递归调用时 需要为过程中使用的参数 局部变量等另外分配存储空间 每层递归调用需分配的空间形成递归工作记录 按后进先出的栈组织 局部变量返回地址参数 活动记录框架 递归工作记录 67 函数递归时的活动记录 Function 调用块 函数块 返回地址 下一条指令 局部变量参数 68 计算Fact时活动记录的内容 递归调用序列 01RetLoc2 11RetLoc2 22RetLoc2 36RetLoc2 424RetLoc1 参数返回值返回地址返回时的指令 return4 6 返回24 return3 2 返回6 return1 返回1 return1 1 返回1 return2 1 返回2 69 递归过程改为非递归过程 递归过程简洁 易编 易懂递归过程效率低 重复计算多改为非递归过程的目的是提高效率尾递归可直接用迭代实现其非递归过程其他情形必须借助栈实现非递归过程 70 调用次数NumCall k 2 Fib k 1 1 斐波那契数列的递归调用树 Fib 1 Fib 0 Fib 1 Fib 2 Fib 3 Fib 4 Fib 1 Fib 0 Fib 2 Fib 1 Fib 0 Fib 1 Fib 2 Fib 3 Fib 5 71 斐波那契数列的非递归实现 longFibIter longn if n 1 returnn longtwoback 0 oneback 1 Current for inti 2 i n i Current twoback oneback twoback oneback oneback Current returnCurrent 72 voidrecfunc intA intn 逆序打印数组元素if n 0 cout A n n recfunc A n 具有尾递归的函数 2536721899495463 尾递归用迭代法实现 73 voidsterfunc intA intn 消除了尾递归的非递归函数while n 0 cout A n endl n 74 递归与回溯 对一个包含有许多结点 且每个结点有多个分支的问题 可以先选择一个分支进行搜索 当搜索到某一结点 发现无法再继续搜索下去时 可以沿搜索路径回退到前一结点 沿另一分支继续搜索 如果回退之后没有其他选择 再沿搜索路径回退到更前结点 依次执行 直到搜索到问题的解 或将全部可搜索的分支都搜索完确认没有解存在为止 回溯法与分治法本质相同 可用递归求解 75 在n行n列的国际象棋棋盘上 若两个皇后位于同一行 同一列 同一对角线上 则称它们为互相攻击 n皇后问题是指找到这n个皇后的互不攻击的布局 举例 n皇后问题 76 1 主对角线3 主对角线5 主对角线 0 次对角线2 次对角线4 次对角线6 次对角线 1 次对角线3 次对角

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论