第三 章 栈和队列_第1页
第三 章 栈和队列_第2页
第三 章 栈和队列_第3页
第三 章 栈和队列_第4页
第三 章 栈和队列_第5页
已阅读5页,还剩46页未读 继续免费阅读

下载本文档

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

文档简介

1、v栈栈 v队列队列 v递归递归 第三章第三章 栈和队列栈和队列 栈栈 ( Stack ) 定义定义:是限定仅在表尾进行插入或删除操是限定仅在表尾进行插入或删除操 作的线性表。作的线性表。 允许插入和删除的一端允许插入和删除的一端 称为栈顶称为栈顶(top),另一端,另一端 称为栈底称为栈底(bottom) 特点:特点:后进先出后进先出 (LIFO) a1 top bottom an . . . . 进栈进栈 出栈出栈 栈的主要操作栈的主要操作 ADT Stack /对象由数据类型为对象由数据类型为StackData的元素构成的元素构成 int Push (stack *S, StackData

2、 x); /进栈进栈 int Pop (stack *S, StackData /出栈出栈 int GetTop (stack *S, StackData /取栈顶取栈顶 void InitStack (stack *S); /置空栈置空栈 int StackEmpty (stack *S); /判栈空否判栈空否 int StackFull (stack *S); /判栈满否判栈满否 top 空栈 top top toptop top a 进栈b 进栈 aa b a b c d e e 进栈 a b c d e f 进栈溢出 a b d e e 退栈 c top c 退栈b 退栈 a b a

3、a 退栈空空栈 top a b d d 退栈 c top a b c top top (1) 设有编号为1,2,3,4,5,6的六辆列车, 顺 序开入栈式结构的站台, 则可能的出栈序 列有多少种? (2) 若进站的六辆列车顺序如上所述, 那么 是否能够得到435612, 325641, 154623 和135426的出站序列, 如果不能, 说明为 什么不能; 如果能, 说明如何得到(即写出 进栈或出栈的序列)。 顺序栈的类型表示顺序栈的类型表示: : #define STACK_INIT_SIZE 100; #define STACKINCREMENT 10; typedef char Sta

4、ckData; typedef struct /顺序栈定义顺序栈定义 StackData *base; /栈底指针栈底指针 StackData *top; /栈顶指针栈顶指针 int Astacksize;/当前已分配的存储空间当前已分配的存储空间 SeqStack; 判栈空判栈空 int StackEmpty (SeqStack *S) if( S-top = S-base ) return 1 /判栈空判栈空,空则空则 返回返回1 else return 0; /否则返回否则返回0 判栈满判栈满 int StackFull (SeqStack *S) if( S-top- S-base =

5、 S- StackSize ) return 1 /判栈满判栈满,满则返回满则返回1 else return 0; /否则返回否则返回0 顺序栈的基本运算顺序栈的基本运算: 入栈入栈 int Push (SeqStack *S, StackData x) /插入元素插入元素x为新的栈顶元素为新的栈顶元素 if ( StackFull (S) exit(overflow); S-top+; S-as- top=x; Return ok 取栈顶元素取栈顶元素 int Gettop (SeqStack *S, StackData x =S-as-top; return 1; 出栈出栈 int pop

6、 (SeqStack *S, StackData x) /若栈空返回若栈空返回0, 否则栈顶元素退出到否则栈顶元素退出到x并返回并返回1 if ( StackEmpty(S) ) return 0; x = as-top; -(-(S-top); return 1; 栈的应用举例栈的应用举例 数制转换数制转换 行编辑程序行编辑程序 迷宫求解迷宫求解 表达式求值表达式求值 数制转换数制转换 N = (N div d)d + N mod d 例如:(例如:(1348)10 = (2504)8 ,其运算过程如下:,其运算过程如下: N N div 8 N mod 8 1348 168 4 168 2

7、1 0 21 2 5 2 0 2 输出顺序输出顺序 计算顺序计算顺序 void conversion () InitStack(S); scanf (%d,N); while (N) Push(S, N % 8); N = N/8; while (!StackEmpty(S) Pop(S,e); printf ( %d, e ); / conversion 行编辑程序行编辑程序 在用户输入一行的过程中,允许在用户输入一行的过程中,允许 用户输入出用户输入出 差错,并在发现有误时可以及时更正。差错,并在发现有误时可以及时更正。 设立一个输入缓冲区,用以接受用户输入的设立一个输入缓冲区,用以接受用

8、户输入的 一行字符,然后逐行存入用户数据区一行字符,然后逐行存入用户数据区; 并假设并假设 “#”为退格符,为退格符,“”为退行符。为退行符。 假设从终端接受两行字符:假设从终端接受两行字符: whli#ilr#e(s#*s) outchaputchar(*s=#+); 实际有效行为:实际有效行为: while (*s) putchar(*s+); Void LineEdit() InitStack(s); ch=getchar(); while (ch != EOF) /EOF为全文结束符为全文结束符 while (ch != EOF break; case : ClearStack(S);

9、 break; / 重置重置S为空栈为空栈 default : Push(S, ch); break; ch = getchar(); / 从终端接收下一个字符从终端接收下一个字符 将从栈底到栈顶的字符传送至调用过程的将从栈底到栈顶的字符传送至调用过程的 数据区;数据区; ClearStack(S); / 重置重置S为空栈为空栈 if (ch != EOF) ch = getchar(); DestroyStack(s); v迷宫求解迷宫求解 通常用的是通常用的是“穷举求解穷举求解”的方法的方法 # # #$# # #$# # $ $# # # # # # # # # # # # v迷宫路径算

10、法的基本思想迷宫路径算法的基本思想 若当前位置若当前位置“可通可通”,则纳入路径,继续,则纳入路径,继续 前进前进; 若当前位置若当前位置“不可通不可通”,则后退,换方向,则后退,换方向 继续探索继续探索; 若四周若四周“均无通路均无通路”,则将当前位置从路,则将当前位置从路 径中删除出去。径中删除出去。 例如例如: Exp = a b + (c d / e) f 前缀式前缀式: + a b c / d e f 中缀式中缀式: a b + c d / e f 后缀式后缀式: a b c d e / f + 表达式标识方法表达式标识方法 b - c a / * de f * + 后缀表达式求值后

11、缀表达式求值 先找运算符,再找操作数先找运算符,再找操作数 例如:例如: a b c d e / f + a b d/e c-d/e (c-d/e) f 从原表达式求得后缀式方法从原表达式求得后缀式方法 设立暂存设立暂存运算符运算符的的栈栈; 设表达式的结束符为设表达式的结束符为“#”, 予设予设运算符栈的运算符栈的 栈底为栈底为“#” 若若当前字符当前字符是操作数是操作数,则,则直接发送给后缀式直接发送给后缀式 ; 若若当前当前运算符的运算符的优先数高优先数高于栈顶运算符,则于栈顶运算符,则 进栈进栈; 否则,退出栈顶运算符发送给后缀式否则,退出栈顶运算符发送给后缀式; “(” 对它之前后的

12、运算符对它之前后的运算符起隔离作用起隔离作用,“)” 为自左括弧开始的表达式的结束符。为自左括弧开始的表达式的结束符。 队列队列 定义定义:只允许在表的一端进行插入,而在只允许在表的一端进行插入,而在 另一端删除元素的线性表。另一端删除元素的线性表。 在队列中,允许插入的一端叫队尾在队列中,允许插入的一端叫队尾(rear) ,允许删除的一端称为对头允许删除的一端称为对头(front)。 特点:特点:先进先出先进先出 (FIFO) a1 ,a2, a3,an 出队列出队列入队列入队列 队队 头头 队队 尾尾 队列的进队和出队队列的进队和出队 front rear 空队列空队列frontrear

13、A,B,C, D进队进队 A B C D frontrear A,B出队出队 C D front rear E,F,G进队进队 C D E F G C D E F G front rear H进队进队,溢出溢出 在非空队列中,头指针始终指向队列头元素,而在非空队列中,头指针始终指向队列头元素,而 尾指针始终指向队列尾元素的下一个位置。尾指针始终指向队列尾元素的下一个位置。 队队 满时再进队将溢出满时再进队将溢出 解决办法:将顺序队列臆造为一个环状的空间,解决办法:将顺序队列臆造为一个环状的空间, 形成循环形成循环(环形环形)队列队列 循环队列循环队列 (Circular Queue) 在非空队

14、列中,头指针始终指向队列头元素,而在非空队列中,头指针始终指向队列头元素,而 尾指针始终指向队列尾元素的下一个位置。尾指针始终指向队列尾元素的下一个位置。 队满时再进队将溢出队满时再进队将溢出 解决办法:将顺序队列臆造为一个环状的空间,解决办法:将顺序队列臆造为一个环状的空间, 形成循环形成循环(环形环形)队列队列 队头、队尾指针加队头、队尾指针加1,可用取模,可用取模(余数余数)运算实现。运算实现。 队头指针进队头指针进1: front = (front+1) %maxsize; 队尾指针进队尾指针进1: rear = (rear+1) % maxsize; 队列初始化:队列初始化:fron

15、t = rear = 0; 队空条件:队空条件:front = rear; 队满条件:队满条件:(rear+1) % maxsize = front; 0 1 23 4 5 67 循环队列循环队列 front rear Maxsize-1 0 1 2 3 4 5 67 front B CD rear 一般情况一般情况 A C 0 1 23 4 5 67 队满队满 front rear D E F G A B C H 0 1 23 4 5 67rear 空队列空队列 front C 0 1 23 4 5 6 7 队满队满(正确正确) front rear D E F G A B C #defin

16、e MAXSIZE 100 Typedef struct QueueData *data; int front; int rear; SeqQueue 循环队列的类型定义循环队列的类型定义 循环队列操作的实现循环队列操作的实现 初始化队列初始化队列 void InitQueue ( SeqQueue *Q ) /构造空队列构造空队列 Q-data=(QueueData *)malloc(MAXSIZE *sizeof(QueueData); If(! Q-data)exit(OVERFLOW); Q-rear = Q-front = 0; Return ok 判队空判队空 int QueueE

17、mpty ( SeqQueue *Q ) return Q-rear = Q-front; 判队满判队满 int QueueFull ( SeqQueue *Q ) return (Q-rear+1) % QueueSize = Q-front; 入队入队 int EnQueue ( SeqQueue *Q, QueueData x ) if ( QueueFull (Q) ) return 0; Q-dataQ-rear = x; Q-rear = ( Q-rear+1) % MAXSIZE; return 1; 出队出队 int DeQueue ( SeqQueue *Q, QueueDa

18、ta x = Q-dataQ-front; Q-front = ( Q-front+1) % MAXSIZE; return 1; 取队头取队头 int GetFront ( SeqQueue *Q, QueueData x = Q-data(Q-front+1) % MAXSIZE; return 1; 链队列:队列的链式表示链队列:队列的链式表示 链队列中,有两个分别指示队头和队尾链队列中,有两个分别指示队头和队尾 的指针。的指针。 链式队列在进队时无队满问题,但有队链式队列在进队时无队满问题,但有队 空问题。空问题。 data next front rear data next fron

19、t rear 递递 归归 定义定义若一个对象部分地包含它自己若一个对象部分地包含它自己, 或用或用 它自己给自己定义它自己给自己定义, 则称这个对象是递归的;则称这个对象是递归的; 若一个过程直接地或间接地调用自己若一个过程直接地或间接地调用自己, 则称这个过程是递归的过程。则称这个过程是递归的过程。 三种递归情况三种递归情况 定义是递归的定义是递归的 数据结构是递归的数据结构是递归的 问题的解法是递归的问题的解法是递归的 定义是递归的定义是递归的 求解阶乘函数的递归算法求解阶乘函数的递归算法 long Factorial ( long n ) if ( n = 0 ) return 1; e

20、lse return n * Factorial (n- -1); 例例1.阶乘函数阶乘函数 时时当当 时时当当 1 ,)!1( 0 , 1 ! n n nn n 求解阶乘求解阶乘 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 参参 数数 传传 递递 结结 果果 返返 回回 例例2.计算斐波那契数列函数计算

21、斐波那契数列函数Fib(n)的定义的定义 递归算法递归算法 long Fib ( long n ) if ( n -link = NULL ) printf (“%dn”, f -data ); else Search ( f -link ); f f f f f a0 a1a2a3a4 递归找链尾 例例2.在链表中寻找等于给定值的结点在链表中寻找等于给定值的结点,并打并打 印其数值印其数值 void Search ( ListNode *f, ListData else Search ( f - link, x ); f f f f 递归找含x值的结点 x 例如,汉诺塔例如,汉诺塔(Towe

22、r of Hanoi)问题的解法:问题的解法: 如果如果 n = 1,则将这一个盘子直接从,则将这一个盘子直接从 A 柱移柱移 到到 C 柱上。否则,执行以下三步:柱上。否则,执行以下三步: 用用 C 柱做过渡,将柱做过渡,将 A 柱上的柱上的 (n- -1) 个盘个盘 子移到子移到 B 柱上:柱上: 将将 A 柱上最后一个盘子直接移到柱上最后一个盘子直接移到 C 柱上;柱上; 用用 A 柱做过渡,将柱做过渡,将 B 柱上的柱上的 (n- -1) 个盘个盘 子移到子移到 C 柱上。柱上。 v问题的解法是递归的问题的解法是递归的 算法算法 #include #include strclass.h

23、” void Hanoi (int n, String A, String B, String C) /解决汉诺塔问题的算法解决汉诺塔问题的算法 if ( n = 1 ) printf ( move %s,A, to %s,C); else Hanoi ( n- -1, A, C, B ); printf ( move %s,A, to %s,C); Hanoi ( n- -1, B, A, C ); 递归过程与递归工作栈递归过程与递归工作栈 n递归过程在实现时,需要自己调用自己。递归过程在实现时,需要自己调用自己。 n层层向下递归,退出时的次序正好相反:层层向下递归,退出时的次序正好相反: 递归调用递归调用 n! (n-1)! (n-2)! 1! 0!=1 返回次序返回次序 n主程序第一次调用递归过程为外部调用;主程序第一次调用递归过程为外部调用; n递归过程每次递归调用自己为内部调用。递归过程每次递归调用自己为内部调用。 递归工作栈递归工作栈 n每一次递归调用时,需要为过程中使用每一次递归调用时,需要为过

温馨提示

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

评论

0/150

提交评论