数据结构之栈
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
计算机解迷宫时,通常用的是“穷举求解”的方法, 即从入口出发,顺某一方向向前探索,若能走通,则继续 往前走;否则沿原路退回,换一个方向再继续探索,直至 所有可能的通路都探索到为止,如果所有可能的通路都试探 过,还是不能走到终点,那就说明该迷宫不存在从起点到 终点的通道。
先看两个动画演示的例子。
第23页/共66页
( 5-5-1.swf)
第24页/共66页
( 5-5-2.swf)
第25页/共66页
由此,求迷宫中一条路径的算法的 基本思想是:
若当前位置"可通",则纳入"当前 路径",并继续朝"下一位置"探索;若当 前位置"不可通",则应顺着"来的方向"退 回到"前一通道块",然后朝着除"来向"之 外的其他方向继续探索;若该通道块的 四周四个方块均"不可通",则应从"当前 路径"上删除该通道块。
第10页/共66页
练习
1、若已知一个栈的入栈顺序是1,2,3,…,n,其输 出序列为P1,P2,P3,…,Pn,若P1是n,则Pi是(C )。 A)i B)n-1 C)n-i+1 D)不确定
2、以下哪一个不是栈的基本运算( B )。 A)删除栈顶元素 B)删除栈底的元素 C)判断栈是否为空 D)将栈置为空栈
end;
procedure pop(var s:stack;var x:integer); begin if s.top=0 then begin writeln(‘Stack empty!’); halt end else begin x:=s.data[s.top]; s.top:=s.top-1 end
读,出错;若top<>0,则回送栈顶元 素的值stack[top]。
第5页/共66页
(4)进栈(push) 将栈顶指针加1后,再把新元素送到栈顶。假
设新元素x为整型,栈的最大深度为n,x和n设置 为值型参。而栈和栈顶指针要设置成变量型参。
procedure push(var stack:arraytype; var top:integer;n:integer;x:integer);
求迷宫中一条从入口到出口的路径 的伪码算法如下:
第26页/共66页
设定当前位置的初值为入口位置; while 栈不空 begin 若当前位置可通, 则begin 将当前位置插入栈顶; { 纳入路径 } 若该位置是出口位置,则算法结束; {此时栈中存放的是一条从入口位置 到出口位置的路径}
type arraytype= array[1.. n] of integer; var stack:arraytype;
top:integer; 再在程序开始时,置top:=0;
第4页/共66页
(2)测试栈 测试栈顶指针的值,若top=0,则
栈空;若top=n,则栈满。
(3)读栈 若top=0,则栈空,无栈顶元素可
一、栈的概念和特性
栈是一种线性表,对它的插入和删除都限制在表的同一端进行。
例子: 一摞碗 弹夹
栈中元素的进出是按后进先出的原则进 行,这是栈结构的重要特征。因此栈又称 为后进先出(LIFO—Last In First Out)表
第1页/共66页
栈的主要运算:
建 栈 ⑴ 在 使 用 栈 之 前 , 首 先 需 要 建 立 一 个 空 栈 , 称
;
进栈(压栈) ⑵往栈顶加入一个新元素,称
;
(退栈、弹出) ⑶删除栈顶元素,称出栈
;
读 栈 ⑷ 查 看 当 前 的 栈 顶 元 素 , 称
;
来自百度文库
测 试 栈 ⑸ 在 使 用 栈 的 过 程 中 , 还 要 不 断 测 试 栈 是 否 为 空 或 已 满 , 称 为
。
第2页/共66页
二、栈的存储结构
栈很适合用一维数组来建立。
第14页/共66页
{对于输入的任意一个非负十进制整数 打印输出与其等值的八进制数}
begin S.top=0; {构造空栈} Readln(n); {输入一个十进制数}
while(n>0)
begin
Push(s,n mod 8); {"余数"入栈}
n = n div 8;
{非零"商"继续运算}
end
第22页/共66页
例5.5:迷宫求解
【问题描述】迷宫求解 你做过迷宫的游戏吗?从入口进去后是如何找到出口的?
如果你不了解迷宫结构显然只能是摸索着前进,比 如先往一个方向走,若走不通那就只能退回来再试试另一 个方向。但在走的过程中你一定会有意识地“记住” 你已 经走过的路,否则你会被困在迷宫中永远也走不出来了。
3、设栈S的初始状态为空,现有5个元素组成的序列 {1,2,3,4,5},对该序列在S 栈上依次进行如下操作(从序列 中的1开始,出栈后不再进栈):进栈,进栈,进栈,出栈,进栈, 出栈,进栈,问出栈的元素序列是:_________,栈顶指针的 值为______,栈顶元素为:______。
解答:出栈序列为{3,4},栈顶指针值为3,栈顶元
现在的问题是,要求检验一个给定表达式中的 括弧是否正确匹配?
第20页/共66页
例如考虑下列括号序列: [( [ ][ ] ) ]
12345678
当计算机接受了第一个括号后,它期待着 与其匹配的第八个括号的出现,然而等来的却是 第二个括号,此时第一个括号"["只能暂时靠边, 而迫切等待与第二个括号相匹配的第七个括号"]" 的出现,类似地,因等来的是第三个括号"[",其 期待匹配的程度较第二个括号更急迫,则第二个 括号也只能靠边,让位于第三个括号,在接受了 第四个括号之后,第三个括号的期待得到满足, 消解之后,第二个括号的期待匹配就成为当前最 急迫的任务了,…,依次类推。
素为5。
第11页/共66页
四、栈的应用
例 5. 1:数制转换
十进制数N和其他d进制数的转换是计算机 实现计算的基本问题,其解决方法很多,其中 一个简单算法基于下列原理:
N = (N div d)×d + N mod d (其中:div 为整除运算,mod 为求余运算)
例如:(1348)10 = (2504)8 ,其运算过程如动 画演示所示:
type stack=record data:array[1..n] of
integer;
{n为栈可达到的最大深度}
top:integer; end;
第8页/共66页
procedure push(var s:stack;x:integer); begin if s.top=n
then begin writeln(‘Stack full!’); halt end else begin s.top:=s.top+1; s.data[s.top]:= x end
while (s.top<>0))
begin {和"求余"所得相逆的顺序输出八进制的各位数}
Pop(S,e);
print e;
end
end.
第15页/共66页
例5. 2:程序员输入问题
程序员输入程序,出现差错时可以采取以下的 补救措施:敲错了一个键时,可以补敲一个退格 符“#”,以表示前一个字符无效;发现当前一 行有错,可以敲入一个退行符“@”,以表示 “@”与前一个换行符之间的字符全部无效。
procedure pop(var s:stack);{出栈} begin if s.top=0 then writeln(‘underflow’) else s.top:=s.top -1; end;
procedure push(var s:stack;x:char); {入栈} begin if s.top=100 then writeln(‘overflow’) else begin s.top:=s.top+1;s.data[s.top]:=x end
栈的溢出
如果一个栈已经为空,但用户还继续做出栈(读栈)操作,则会出现栈的 “下溢”;如果一个栈已经满了,用户还继续做进栈操作,则会出现栈的 “上溢”。两种情况统称为栈的溢出。
第3页/共66页
三、对栈的几种运算的实现方法:
(1)建栈 这比较简单,只要建立一个一维数组,
再把栈顶指针置为零。栈的容量根据具体 的应用要求而定。比如:
第21页/共66页
上面列举的三种错误匹配从“期待匹配”的 角度描述即为:
1.来的右括弧非是所"期待"的; 2.来的是"不速之客"; 3.直到结束,也没有到来所"期待"的。
这三种情况对应到栈的操作即为: 1.和栈顶的左括弧不相匹配; 2.栈中并没有左括弧等在哪里; 3.栈中还有左括弧没有等到和它 相匹配的右括弧。
top:integer;var x:integer); begin if top=0 then begin writeln(‘Stack empty!’); halt end else begin x:=stack[top]; top:=top-1 end
end;
第7页/共66页
栈的记录方式实现方法
第12页/共66页
( 5-4-1.swf)
假设现要编制一个满足下列要求的程序: 对于输入的任意一个非负十进制整数,打 印输出与其等值的八进制数。
第13页/共66页
算法 5. 1 Program p5_1(input,output); type
stack=record data:array[1..100] of integer; top:0..100; end; var n:integer; e:integer; s:stack
end;
第18页/共66页
Begin {主程序} while not eof do {eof为全文结束符}
begin
setnull(s);
while not eoln do {eoln为行结束符}
begin
read(ch);
case ch of
‘#’:pop(s); {出栈} ‘@’:setnull(s) {置栈为空}
program p5_2 (input,output); type
stack=record data:array[1..100] of char; top:0..100;
end; var
s:stack;ch:char;i:integer;
第17页/共66页
procedure setnull(var s:stack);{置栈为空} begin s.top:=0 end;
end;
第9页/共66页
出栈有时也可用函数实现,如:
function pop(var s:stack):integer; begin if s.top=0 then begin writeln(‘Stack empty!’); halt end else begin pop:=s.data[s.top]; s.top:=s.top-1 end end;
else push(s,ch) {入栈}
end;
end;
for i:=1 to s.top do write(s.data[i]); {输出} writeln; read(ch);
end End.
第19页/共66页
例5. 3:括弧匹配检验
假设表达式中允许包含两种括号:圆括号和方 括号,其嵌套的顺序随意,如([ ]())或 [([ ][ ])]等为正确的匹配,[( ]) 或([ ]( )或 ( ( ) ) )均为错误的匹配 。
例如: 设一维数组STACK[1..n] 表示一个栈,其中n为栈的容量,即可存放元素的
最大个数。栈底元素,是存放在STACK[1]处,第二个元素存放在STACK[2] 处,第i个元素存放在STACK[i]。
设置一个指针变量top,用来指示栈顶当前位置,栈中没有元素即栈空时, 令top=0,当top=n时,表示栈满。
begin if top=n then
begin writeln(‘Stack full!’); halt end else begin
top:=top+1; stack[top]:= x end end;
第6页/共66页
(5) 退栈(pop) 取得栈顶元素的值后,再把栈顶指针top减
1。注意都用变量型参。 procedure pop(var stack:arraytype;var
如:在终端上输入了这样两行字符 PRKJ##OGRAN#M LX; VAR@CONST N:#=10;
则实际有效的是: PROGRAM LX; CONST N=10第;16页/共66页
分析:可在程序中设一个栈来逐行处理从终端输 入的字符串。每次从终端接受一个字符后作如下 判别:既不是退格符#也不是退行符@,则将该 字符插入栈顶;是退格符#,则从栈顶删去一个 字符;是退行符@ ,就把字符栈清为空栈。
先看两个动画演示的例子。
第23页/共66页
( 5-5-1.swf)
第24页/共66页
( 5-5-2.swf)
第25页/共66页
由此,求迷宫中一条路径的算法的 基本思想是:
若当前位置"可通",则纳入"当前 路径",并继续朝"下一位置"探索;若当 前位置"不可通",则应顺着"来的方向"退 回到"前一通道块",然后朝着除"来向"之 外的其他方向继续探索;若该通道块的 四周四个方块均"不可通",则应从"当前 路径"上删除该通道块。
第10页/共66页
练习
1、若已知一个栈的入栈顺序是1,2,3,…,n,其输 出序列为P1,P2,P3,…,Pn,若P1是n,则Pi是(C )。 A)i B)n-1 C)n-i+1 D)不确定
2、以下哪一个不是栈的基本运算( B )。 A)删除栈顶元素 B)删除栈底的元素 C)判断栈是否为空 D)将栈置为空栈
end;
procedure pop(var s:stack;var x:integer); begin if s.top=0 then begin writeln(‘Stack empty!’); halt end else begin x:=s.data[s.top]; s.top:=s.top-1 end
读,出错;若top<>0,则回送栈顶元 素的值stack[top]。
第5页/共66页
(4)进栈(push) 将栈顶指针加1后,再把新元素送到栈顶。假
设新元素x为整型,栈的最大深度为n,x和n设置 为值型参。而栈和栈顶指针要设置成变量型参。
procedure push(var stack:arraytype; var top:integer;n:integer;x:integer);
求迷宫中一条从入口到出口的路径 的伪码算法如下:
第26页/共66页
设定当前位置的初值为入口位置; while 栈不空 begin 若当前位置可通, 则begin 将当前位置插入栈顶; { 纳入路径 } 若该位置是出口位置,则算法结束; {此时栈中存放的是一条从入口位置 到出口位置的路径}
type arraytype= array[1.. n] of integer; var stack:arraytype;
top:integer; 再在程序开始时,置top:=0;
第4页/共66页
(2)测试栈 测试栈顶指针的值,若top=0,则
栈空;若top=n,则栈满。
(3)读栈 若top=0,则栈空,无栈顶元素可
一、栈的概念和特性
栈是一种线性表,对它的插入和删除都限制在表的同一端进行。
例子: 一摞碗 弹夹
栈中元素的进出是按后进先出的原则进 行,这是栈结构的重要特征。因此栈又称 为后进先出(LIFO—Last In First Out)表
第1页/共66页
栈的主要运算:
建 栈 ⑴ 在 使 用 栈 之 前 , 首 先 需 要 建 立 一 个 空 栈 , 称
;
进栈(压栈) ⑵往栈顶加入一个新元素,称
;
(退栈、弹出) ⑶删除栈顶元素,称出栈
;
读 栈 ⑷ 查 看 当 前 的 栈 顶 元 素 , 称
;
来自百度文库
测 试 栈 ⑸ 在 使 用 栈 的 过 程 中 , 还 要 不 断 测 试 栈 是 否 为 空 或 已 满 , 称 为
。
第2页/共66页
二、栈的存储结构
栈很适合用一维数组来建立。
第14页/共66页
{对于输入的任意一个非负十进制整数 打印输出与其等值的八进制数}
begin S.top=0; {构造空栈} Readln(n); {输入一个十进制数}
while(n>0)
begin
Push(s,n mod 8); {"余数"入栈}
n = n div 8;
{非零"商"继续运算}
end
第22页/共66页
例5.5:迷宫求解
【问题描述】迷宫求解 你做过迷宫的游戏吗?从入口进去后是如何找到出口的?
如果你不了解迷宫结构显然只能是摸索着前进,比 如先往一个方向走,若走不通那就只能退回来再试试另一 个方向。但在走的过程中你一定会有意识地“记住” 你已 经走过的路,否则你会被困在迷宫中永远也走不出来了。
3、设栈S的初始状态为空,现有5个元素组成的序列 {1,2,3,4,5},对该序列在S 栈上依次进行如下操作(从序列 中的1开始,出栈后不再进栈):进栈,进栈,进栈,出栈,进栈, 出栈,进栈,问出栈的元素序列是:_________,栈顶指针的 值为______,栈顶元素为:______。
解答:出栈序列为{3,4},栈顶指针值为3,栈顶元
现在的问题是,要求检验一个给定表达式中的 括弧是否正确匹配?
第20页/共66页
例如考虑下列括号序列: [( [ ][ ] ) ]
12345678
当计算机接受了第一个括号后,它期待着 与其匹配的第八个括号的出现,然而等来的却是 第二个括号,此时第一个括号"["只能暂时靠边, 而迫切等待与第二个括号相匹配的第七个括号"]" 的出现,类似地,因等来的是第三个括号"[",其 期待匹配的程度较第二个括号更急迫,则第二个 括号也只能靠边,让位于第三个括号,在接受了 第四个括号之后,第三个括号的期待得到满足, 消解之后,第二个括号的期待匹配就成为当前最 急迫的任务了,…,依次类推。
素为5。
第11页/共66页
四、栈的应用
例 5. 1:数制转换
十进制数N和其他d进制数的转换是计算机 实现计算的基本问题,其解决方法很多,其中 一个简单算法基于下列原理:
N = (N div d)×d + N mod d (其中:div 为整除运算,mod 为求余运算)
例如:(1348)10 = (2504)8 ,其运算过程如动 画演示所示:
type stack=record data:array[1..n] of
integer;
{n为栈可达到的最大深度}
top:integer; end;
第8页/共66页
procedure push(var s:stack;x:integer); begin if s.top=n
then begin writeln(‘Stack full!’); halt end else begin s.top:=s.top+1; s.data[s.top]:= x end
while (s.top<>0))
begin {和"求余"所得相逆的顺序输出八进制的各位数}
Pop(S,e);
print e;
end
end.
第15页/共66页
例5. 2:程序员输入问题
程序员输入程序,出现差错时可以采取以下的 补救措施:敲错了一个键时,可以补敲一个退格 符“#”,以表示前一个字符无效;发现当前一 行有错,可以敲入一个退行符“@”,以表示 “@”与前一个换行符之间的字符全部无效。
procedure pop(var s:stack);{出栈} begin if s.top=0 then writeln(‘underflow’) else s.top:=s.top -1; end;
procedure push(var s:stack;x:char); {入栈} begin if s.top=100 then writeln(‘overflow’) else begin s.top:=s.top+1;s.data[s.top]:=x end
栈的溢出
如果一个栈已经为空,但用户还继续做出栈(读栈)操作,则会出现栈的 “下溢”;如果一个栈已经满了,用户还继续做进栈操作,则会出现栈的 “上溢”。两种情况统称为栈的溢出。
第3页/共66页
三、对栈的几种运算的实现方法:
(1)建栈 这比较简单,只要建立一个一维数组,
再把栈顶指针置为零。栈的容量根据具体 的应用要求而定。比如:
第21页/共66页
上面列举的三种错误匹配从“期待匹配”的 角度描述即为:
1.来的右括弧非是所"期待"的; 2.来的是"不速之客"; 3.直到结束,也没有到来所"期待"的。
这三种情况对应到栈的操作即为: 1.和栈顶的左括弧不相匹配; 2.栈中并没有左括弧等在哪里; 3.栈中还有左括弧没有等到和它 相匹配的右括弧。
top:integer;var x:integer); begin if top=0 then begin writeln(‘Stack empty!’); halt end else begin x:=stack[top]; top:=top-1 end
end;
第7页/共66页
栈的记录方式实现方法
第12页/共66页
( 5-4-1.swf)
假设现要编制一个满足下列要求的程序: 对于输入的任意一个非负十进制整数,打 印输出与其等值的八进制数。
第13页/共66页
算法 5. 1 Program p5_1(input,output); type
stack=record data:array[1..100] of integer; top:0..100; end; var n:integer; e:integer; s:stack
end;
第18页/共66页
Begin {主程序} while not eof do {eof为全文结束符}
begin
setnull(s);
while not eoln do {eoln为行结束符}
begin
read(ch);
case ch of
‘#’:pop(s); {出栈} ‘@’:setnull(s) {置栈为空}
program p5_2 (input,output); type
stack=record data:array[1..100] of char; top:0..100;
end; var
s:stack;ch:char;i:integer;
第17页/共66页
procedure setnull(var s:stack);{置栈为空} begin s.top:=0 end;
end;
第9页/共66页
出栈有时也可用函数实现,如:
function pop(var s:stack):integer; begin if s.top=0 then begin writeln(‘Stack empty!’); halt end else begin pop:=s.data[s.top]; s.top:=s.top-1 end end;
else push(s,ch) {入栈}
end;
end;
for i:=1 to s.top do write(s.data[i]); {输出} writeln; read(ch);
end End.
第19页/共66页
例5. 3:括弧匹配检验
假设表达式中允许包含两种括号:圆括号和方 括号,其嵌套的顺序随意,如([ ]())或 [([ ][ ])]等为正确的匹配,[( ]) 或([ ]( )或 ( ( ) ) )均为错误的匹配 。
例如: 设一维数组STACK[1..n] 表示一个栈,其中n为栈的容量,即可存放元素的
最大个数。栈底元素,是存放在STACK[1]处,第二个元素存放在STACK[2] 处,第i个元素存放在STACK[i]。
设置一个指针变量top,用来指示栈顶当前位置,栈中没有元素即栈空时, 令top=0,当top=n时,表示栈满。
begin if top=n then
begin writeln(‘Stack full!’); halt end else begin
top:=top+1; stack[top]:= x end end;
第6页/共66页
(5) 退栈(pop) 取得栈顶元素的值后,再把栈顶指针top减
1。注意都用变量型参。 procedure pop(var stack:arraytype;var
如:在终端上输入了这样两行字符 PRKJ##OGRAN#M LX; VAR@CONST N:#=10;
则实际有效的是: PROGRAM LX; CONST N=10第;16页/共66页
分析:可在程序中设一个栈来逐行处理从终端输 入的字符串。每次从终端接受一个字符后作如下 判别:既不是退格符#也不是退行符@,则将该 字符插入栈顶;是退格符#,则从栈顶删去一个 字符;是退行符@ ,就把字符栈清为空栈。