数据结构堆栈
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
插入:入栈、进栈、压栈 删除:出栈、弹栈
栈的操作特性:后进先出
4.1堆栈的概念及其运算
例:有三个元素按a、b、c的次序依次进栈,且每个 元素只允许进一次栈,则可能的出栈序列有多少种? 情况1:
栈顶
栈顶
出栈序列:c
栈顶 栈底
c b a
出栈序列:c、b
出栈序列:c、b、a
4.1堆栈的概念及其运算
4.2堆栈的顺序存储结构
两栈共享空间:使用一个数组来存储两个栈,让一个 栈的栈底为该数组的始端,另一个栈的栈底为该数组 的末端,两个栈从各自的端点向中间延伸。
4.2堆栈的顺序存储结构
0 1 2 ……
S-1
a 1 a2 … a i
栈1底
bj … … b2 b1
top2
栈2底
top1
栈1的底固定在下标为0的一端; 栈2的底固定在下标为MaxSize-1的一端。 top1和top2分别为栈1和栈2的栈顶指针; MaxSize为整个数组空间的大小(图中用S表示);
4.4堆栈的应用—中缀表达式转换
• 算法思想p81-82 • 关键点:
– 运算符堆栈 – 运算符优先关系表
4.4堆栈的应用—中缀表达式转换
运算优先级
当前运算符
+ - × / ( ) #
+ > > > > < > <
- > > > > < > <
× < < > > < > <
/ < < > > < > <
4.4堆栈的应用——递归
• 汉诺塔问题的递归求解:
– 如果 n = 1,则将这一个盘子直接从 塔A移 到塔 C 上。否则,执行以下三步: – ⑴ 将塔A上的n-1个碟子借助塔C先移到塔B 上; – ⑵ 把塔A上剩下的一个碟子移到塔C上;
– ⑶ 将n-1个碟子从塔B借助于塔A移到塔C上。
4.4堆栈的应用——递归
4.4堆栈的应用—表达式求值
• 后缀表达式实例 (1) ABCE/-E*+
对应中缀表达式 A+(B-C/D)*E
(2)ABCD/F*-E*+X+
对应中缀表达式A+(B-C/D*F)*E+X
4.4堆栈的应用—后缀表达式求值
后缀表达式计算算法:
Procedure EVAL(E) //E为后缀表达式 top0 loop x NEXT_TOKEN(E) case :x=“#”: return :x=运算对象: call PUSH(STACK,M,top,x) :else: 从堆栈中取出相应的运算对象进行由x执行的运算 并将结果入栈 end forever end
• 总之,当栈的使用过程中元素个数变化较大时, 用链栈是适宜的,反之,应该采用顺序栈。
4.4堆栈的应用——递归
• 1 递归的定义
– 子程序(或函数)直接调用自己或通过一系列调用 语句间接调用自己,是一种描述问题和解决问题的 基本方法。
• 2 递归的基本思想
– 问题分解:把一个不能或不好解决的大问题转化为 一个或几个小问题,再把这些小问题进一步分解成 更小的小问题,直至每个小问题都可以直接解决。
4.3堆栈的链式存储结构
操作接口: 入栈:p75 出栈:p75
4.3堆栈的链式存储结构
顺序栈和链栈的比较
• 时间性能:相同,都是常数时间O(1)。 • 空间性能:
– 顺序栈:有元素个数的限制和空间浪费的问题。 – 链栈:没有栈满的问题,只有当内存没有可用空间 时才会出现栈满,但是每个元素都需要一个指针域, 从而产生了结构性开销。
a1
a2
ai
an ∧
将哪一端作为栈顶? 将链头作为栈顶,方便操作。
链栈需要加头结点吗? 链栈不需要附设头结点。
4.3堆栈的链式存储结构
链栈:栈的链接存储结构 head top an
栈顶
a1
a2 a1 ∧
栈底
ai top an
an ∧
栈顶
an-1
an-1
两种示意图在内存中 对应同一种状态 a1 ∧ 栈底
( < < < < <
<
) > > > > = >
# > > > >
> =
栈顶运算符
4.4堆栈的应用—中缀表达式转换
算法: //将中缀表达式E转换为后缀表达式
Procedure POSTFIX(E) STACK[1]=“#” top1 loop x NEXT_TOKEN(E) case :x=“#”: while top>1 do print(STACK[top]) //输出栈顶运算符 call POP(STATCK,top) //退栈 end print(“#”); return :x是运算对象: print(x) //直接输出运算对象 end forever end
Hanio(2,A,C,B) Hanio(1,A,B,C) Hanio(3,A,B,C) Hanio(2,A,C,B) Move (A,B) Hanio(1,C,A,B)
Hanio(1,A,B,C)
Move (A,C)
Hanio(1,C,A,B) Move (C,B)
Move (A,C)
Hanio(2,B,A,C) Hanio(1,B,C,A)
top1= -1 top2
top2= MaxSize
4.2堆栈的顺序存储结构
0 1 2 ……
S-1
a 1 a2 … … ai bj
top1 top2
什么时候栈1为空? 什么时候栈2为空?
…
… b2 b1
top1= -1
top2= MaxSize top2= top1+1
什么时候栈满?
4.2堆栈的顺序存储结构
例:有三个元素按a、b、c的次序依次进栈,且每个 元素只允许进一次栈,则可能的出栈序列有多少种?
情况2:
栈顶
出栈序列:b
栈顶 栈底
b a
4.1堆栈的概念及其运算
例:有三个元素按a、b、c的次序依次进栈,且每个 元素只允许进一次栈,则可能的出栈序列有多少种? 情况2:
栈顶 栈顶 栈底
出栈序列:b
Hanio(1,B,C,A) Move (B,A)
Hanio(2,B,A,C)
Move (B,C)
Hanio(1,A,B,C)
Hanio(1,A,B,C) Move (A,C)
结束
4.4堆栈的应用—表达式求值
• 中缀表达式 • 后缀表达式 • 后缀表达式特点
– 后缀表达式中不出现括号 – 后缀表达式与中缀表达式的运算对象的先后次序 相同,只是所读到的运算符的先后次序可能有所 改变
操作接口:T Pop(int i) ; 1. 若是在栈1删除,则 1.1 若栈1为空栈,抛出下溢异常; 1.2 删除并返回栈1的栈顶元素; 2. 若是在栈2删除,则 2.1 若栈2为空栈,抛出下溢异常; 2.2 删除并返回栈2的栈顶元素;
4.3堆栈的链式存储结构
如何改造链表实现栈的链接存储?
head
4.2堆栈的顺序存储结构
堆栈是否为空测试算法p70
进栈算法p71 退栈算法
4.2堆栈的顺序存储结构
在一个程序中需要同时使用具有相同数据类型的 两个栈,如何顺序存储这两个栈?
解决方案1: 直接解决:为每个栈开辟一个数组空间。
会出现什么问题?如何解决? 解决方案2: 顺序栈单向延伸——使用一个数组来存储两个栈
• 递归函数的内部执行过程
– ⑴ 运行开始时,首先为递归调用建立一个工作栈, 其结构包括值参、局部变量和返回地址; – ⑵ 每次执行递归调用之前,把递归函数的值参和局 部变量的当前值以及调用后的返回地址压栈; – ⑶ 每次递归调用结束后,将栈顶元素出栈,使相应 的值参和局部变量恢复为调用前的值,然后转向返 回地址指定的位置继续执行。
c a
出栈序列:b、c 出栈序列: b、 c、a
注意:栈只是对表插入和删除操作的位置进行了限 制,并没有限定插入和删除操作进行的时间。
4.1堆栈的概念及其运算
堆栈的操作
Push(S,x) Pop(S) Empty(S) Top(S) Create(S)
4.2堆栈的顺序存储结构
如何改造数组实现栈的顺序存储?
4.4堆栈的应用—中缀表达式转换
:x=“)” : while STACK[top] <>”(“ do print(STATCK[top]) call POP(STACK,top) end top top-1 //放弃当前读到的”)”,并且栈顶 “(”退栈 :else: while ISP(STACK[top]>=ICP(x) do print(STACK[top]) call POP(STACK,top) end call PUSH(STACK,top,x) //运算符进栈
end forever end
4.4堆栈的应用——递归
• 递归的经典问题——汉诺塔问题
– 在世界刚被创建的时候有一座钻石宝塔(塔 A),其上有64个金碟。所有碟子按从大到 小的次序从塔底堆放至塔顶。紧挨着这座塔 有另外两个钻石宝塔(塔B和塔C)。从世 界创始之日起,婆罗门的牧师们就一直在试 图把塔A上的碟子移动到塔C上去,其间借 助于塔B的帮助。每次只能移动一个碟子, 任何时候都不能把一个碟子放在比它小的碟 子上面。当牧师们完成任务时,世界末日也 就到了。
0 1 2 3 4 5 6 7 8
a1
top 确定用数组的哪一端表示栈底。 附设指针top指示栈顶元素在数组中的位置。
4.2堆栈的顺序存储结构
0 1 2 3 4 5 6 7 8
a1 a2 a3
top top top 进栈:top加1 出栈:top减1 栈空:top= -1
栈满:top= MAX_SIZE
4.1堆栈的概念及其运算
• 堆栈的逻辑结构
– 堆栈:限定仅在表尾进行插入和删除操作的 线性表。 – 空栈:不含任何数据元素的栈。 – 允许插入和删除的一端称为栈顶,另一端称 为栈底。
(a1, a2, „„, an)
栈底 栈顶
4.1堆栈的概念及其运算
入栈 出栈
栈的示意图
栈顶 栈顶
栈顶 栈底
c b a
4.4堆栈的应用——递归
• 3 递归的要素
– 递归边界条件:确定递归到何时终止,也称 为递归出口; – 递归模式:大问题是如何分解为小问题的, 也称为递归体。
4.4堆栈的应用——递归
例1 阶乘函数
n! =
1 n * ( n - 1 )!
当 n=1 时 当 n≥1 时
递归算法 int fact ( int n ) { if ( n == 0 ) return 1; else return n * fact (n-1); }
操作接口:void Push(int i, T x) ; 1. 如果栈满,则抛出上溢异常; 2. 判断是插在栈1还是栈2; 2.1 若在栈1插入,则 2.1.1 top1加1; 2.1.2 在top1处填入x; 2.2 若在栈2插入,则 2.2.1 top2减1; 2.2.2 在top2处填பைடு நூலகம்x;
4.2堆栈的顺序存储结构
4.2堆栈的顺序存储结构
0 1 2 ……
S-1
a 1 a2 … a i
top1 top1
什么时候栈1为空?
bj … … b2 b1
top2
top1= -1
4.2堆栈的顺序存储结构
0 1 2 ……
S-1
a 1 a2 … a i
top1
什么时候栈1为空? 什么时候栈2为空?
bj … … b2 b1
top2
4.4堆栈的应用——递归
void Hanoi(int n, char A, char B, char C) { if (n==1) Move(A, C); else { Hanoi(n-1, A, C, B); Move(A, C); Hanoi(n-1, B, A, C); } }
4.4堆栈的应用——递归