ch3-2 栈的应用

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

从原表达式求得后缀式的规律为: 1) 2) 3) 设立暂存运算符的栈; 设表达式的结束符为“#”,预设运算符栈的 栈底为“#” 若当前字符是操作数,则直接发送给后缀式;
4)
5)
若当前运算符的优先数高于栈顶运算符,则进栈;
否则,退出栈顶运算符发送给后缀式;
6) “(” 对它之前后的运算符起隔离作用,“)”可 视为自相应左括弧开始的表达式的结束符。
N
计 算 顺 序
N/8 168 21 2 0
N% 8 4 0 5 2
2
1348 168 21 2
输 出 顺 序
设计思路:用栈暂存低位值
void conversion () { InitStack(S); scanf (“%u”,&N);//输入非负整数 while (N) { Push(S, N % 8);//入栈N除以8的余数 ,得8进制的低位; N = N/8; } while (!StackEmpty(S)) { Pop(S,e);//弹出栈顶元素且付给e; printf ( "%d", e ); } 3 } // conversion
12
后缀式:
a bc d+e-
教材P53中表3.1给 出了算符之间的优 先级
a ( b+c d - e)#
已知表达式
+ (
专为计算机处理而设 计的表!
#
13
例4: 汉诺( Hanoi)塔
传说在创世纪时,在一个叫Brahma的寺庙里,有三个柱子,其中 一柱上有64个盘子从小到大依次叠放,僧侣的工作是将这64个盘 子从一根柱子移到另一个柱子上。 x y z 移动时的规则: 每次只能移动一个盘子; 只能小盘子在大盘子上面; n –1 可以使用任一柱子。 n
9
中缀表示法:3*(7-2) 表示法:372-* 思想(后缀):自左至右扫描,如是操作 数,则入栈,遇到运算符,则连续两次 出栈,进行相应运算。
10
例3 :表达式求值 —-————见教材P52(后缀式) 后缀式的运算规则是: 运算符在式中出现的顺序恰为表达式的运算顺序; 每个运算符与在它之前出现且仅靠它的两个操作数 构成一个表达式 如何从原表达式求得后缀式? 分析 “原表达式” 和 “后缀式”中的运算符 : 原表达式: a ( b+c d-e ) 后缀式: a b c d + e 每个运算符的运算次序要由它之后的一个运算符来 定,在后缀式中,优先数高的运算符领先于优先数低 11 的运算符。
24
19
m=4, k=2
Fib(4, 2) 2*Fib(3, 2) 2*Fib(2, 2) 1 2 Fib(0, 2) 0 3 Fib(1, 2) 1
-
-
20
例5. 迷宫求解 (穷举法,自学)
0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
当前位置:某一时刻所在图 中某个方块位置。 当前位置可通:未曾走到过 的通道块,既要求该方块位置 不在当前位置上,也不是曾经 纳入过路径的通道块。 ①回路不能出现,简单路径; ②防止在死胡同内转圈。
递归运算!
16
练习:递归算法计算K阶斐波那契(Fibonacci)数列 的第m项值。 int Fib ( int m, int k) { if( k < 2 || m< 0) return -1; if( m < k-1) return 0; else if( m == k-1 ) return 1; else{ sum = 0; for( i = 1; i <= k; i++) sum += Fib( m - i, k); return sum; }
分析: 设三根柱子分别为 x, y, z , 盘子在 x 柱上,要移到 z 柱上。 1、当 n=1 时,盘子直接从 x 柱移到 z 柱上; 2、当 n>1 时, 则: ① 设法将 前 n –1 个盘子 从 x 移到 y 柱上(借助z),则 盘子 n 就能从 x 移到 z 柱上; ② 再设法把n –1 个盘子 从 y 移到 z 柱上(这又是一个与原来相 同的问题,只是规模少1了) 。
OPND栈和OPTR栈 操作数入OPND栈,算符入OPTR栈
7
θ1<θ2,表明不能进行θ1 的运算,θ2 入栈,读 下一字符。 θ1>θ2,表明可以进行θ1 的运算,θ1退栈,运算, 运算结果入栈。 θ1=θ2,脱括号,读下一字符或表达式结束。
8
#3*(7-2)# 步骤 OPTR栈 OPND栈 输入字符 主要操作 1 # 3*(7-2)# PUSH(OPND,‟3‟) 2 # 3 *(7-2)# PUSH(OPTR,‟*‟) 3 #* 3 (7-2)# PUSH(OPTR,‟(„) 4 #*( 3 7-2)# PUSH(OPND,‟7‟) 5 #*( 37 -2)# PUSH(OPTR,‟-‟) 6 #*(37 2)# PUSH(OPND,‟2‟) 7 #*(372 )# operate(„7‟,‟-‟,‟2‟) 8 #*( 35 )# POP(OPTR) 9 #* 35 # operater(„3‟,‟*‟,‟5‟) 10 # 15 # RETURN
23
迷宫maze的表示:char maze[10][10] ={…}; @:未曾走过;*:在当前路径上; #:墙; X:曾走过。 char **maze; maze = (char **)malloc( m * sizeof (char *) ); for(i=1;i<=n;i++) maze[i] = (char *)malloc( n* sizeof (char ) ); 下一位置:int movei[4] = {1, 0, -1, 0}; int movej[4] = {0, 1, 0, -1}; 设当前位置为e(i, j),则e(i, j)的下一位置: i = e.i + movei[e.dir-1]; j = e.j + movej[e.dir-1]; 当前通道块是否可通: if(maze[i][j] ==@) 可通;
例2:括号匹配的检验————见教材P49 算法的设计思想:
1)凡扫描到(,[,}时,则进栈;
2)凡出现),],}时判断,是否是匹配的括号。 首先检查栈是否空 若栈空,则表明该“右括弧”多余,报错; 否则和栈顶元素比较, 若相匹配,则“左括弧出栈”; 否则,报错。 3)表达式检验结束时, 若栈空,则表明表达式中匹配正确; 否则表明“左括弧”有余,报错。
14
问题的解法是递归的
15
程序设计如下: Void Hanoi ( int n, char x, char y, char z ) { //将n个编号从上到下为1…n的盘子从x柱,借助y柱移到z柱 if ( n = = 1 ) move ( x , 1 , z ) ; //将编号为1的盘子从x柱移到z柱 else { //将n-1个编号从上到下为1…n-1的盘子从x柱,借助y 柱移到z柱 Hanoi ( n-1 , x , z , y ) ; move ( x , n, z) ; //将编号为n的盘子从x柱移到z柱 //将n-1个编号从上到下为1…n-1的盘子从y柱,借助x柱 移到z柱 Hanoi ( n-1 , y , x , z ); } } //Hanoi
设计思路:用栈暂存左括号 此例作为上机实验题
4
5
Status match(char *str) { InitStack(S); for(p=str; *p; p++){ switch(*p){ case „(„: case „[„: case „{„: Push(S, *p); break; case „)‟: Pop(S, e); if(e != „(„) return ERROR; break; case „]‟: Pop(S, e); if(e != „[„) return ERROR; break; case „}‟: Pop(S, e); if(e != „{„) return ERROR; }//switch } //for if(StackEmpty(S)) return OK; }
17
m=4, k=2 Fib(4, 2)
3
Fib(2, 2) Fib(1, 2) 1
Fib(3, 2)
Fib(2, 2) 1 1 0
+
2 Fib(1, 2) 1
+
+
1 Fib(1, 2) 0
Fib(1, 2) + Fib(0, 2)
18
fm 2 fm1 fm( k 1)
int Fib ( int m, int k) { if( k < 2 || m< 0) return -1; if( m < k-1) return 0; else if( m == k-1 || m == k ) return 1; else return 2*Fib( m-1, k) – Fib( m-k-1, k); }
④ ③ ②
下一位置:当前位置四周四 ① 个方向上相邻的方块。
21
从入口到出口的路径算法 设当前位置的初值为入口位置; do{ 若当前位置可通,则{ 将当前位置插入栈顶; 若该位置为出口位置,则结束; 将该位置的东邻块置为当前位置; } 否则{ 若栈不空且栈顶位置尚有其它方向未经探索,则 设定新的当前位置为栈顶位置的下一相邻块; 若栈不空但栈顶位置的四周均不通,则 删去栈顶位置; 若栈不空,则 重新测试新的栈顶位置,直至找到一个可通 的 相邻块或栈至栈空; } 22 }while(栈不空)
6
[([][])] 12345678
例3 :表达式求值
—-————见教材P52(后缀式)
表达式求值(算符优先算法) (delimiter 左右括号和表达式结束符),运算符和界限 符统称算符。
#(7+15)*(23-28/4)# (1) 从左算到右; (2) 先乘除, 后加减; (3) 先括号内, 后括号外。
0 1 2 3 4 5 6 7 8 9
1
2
3
4
5
6
7
8
9
typedef struct{ int ord; //在路径上的序号 int i, j; //坐标 int dir; //当前位置下一方向
}SElemType;
ord i j dir 1 (1, 1) 1 2 (1, 2) 2 3 (2, 2) 2 4 (3, 2) 1 3 5 (3, 3) 1 6 (3, 4) 4 7 (2, 4) 1 8 (2, 5) 1 9 (2, 6) 4 10 (1, 6) 3 11 (1, 5) 3 12 (1, 4) X 13 (3, 1) 2 14 (4, 1) 2
栈的应用举例 例1: 数制转换—— 见教材P48
设计思路:用栈暂存低位值
例2:括号匹配的检验————见教材P49
设计思路:用栈暂存左括号
例3 :表达式求值(自学)-————见教材P52
设计思路:用栈暂存运算符
例4:汉诺(Hanoi)塔(自学)-------材P55
设计思路:用栈实现递归调用
1
例1: 数制转换——见教材P48 例如:(1348)10 = (2504)8 , 算法基于原理: 其运算过程如下: N = (N div d)×d + N mod d
相关文档
最新文档