栈的基本知识及应用

栈的基本知识及应用

  1.栈的概念和特性

  栈(stack)是一种特殊的线性表。作为一个简单的例子,可以把食堂里冼净的一摞碗看作一个栈。在通常情况下,最先冼净的碗总是放在最底下,后冼净的碗总是摞在最顶上。而在使用时,却是从顶上拿取,也就是说,后冼的先取用,后摞上的先取用。好果我们把冼净的碗“摞上”称为进栈(压栈),把“取用碗”称为出栈(弹出),那么,上例的特点是:后进栈的先出栈。然而,摞起来的碗实际上是一个表,只不过“进栈”和“出栈”都在最顶上进行,或者说,元素的插入和删除是在表的一端进行而已。

  一般而言,栈是一个线性表,其所有的插入和删除均是限定在表的一端进行,允许插入和删除的一端称栈顶(Top),不允许插入和删除的一端称栈底(Bottom)。若给定一个栈S=(a

  1,

  a2,a3,?,an),则称a1为栈底元素,an为栈顶元素,元素ai位于元素ai-1之上。栈中元

  素按a1, a2,a3,?,an 的次序进栈,如果从这个栈中取出所有的元素,则出栈次序为an, an-1,?,a1 。也就是说,栈中元素的进出是按后进先出的原则进行,这是栈结构的重要特征。因此栈又称为后进先出(LIFO—Last In First Out)表。

  我们常用一个图来形象地表示栈,其形式如下图:

  通常,对栈进行的运算主要有以下几种:

  ⑴在使用栈之前,首先需要建立一个空栈,称建栈; ⑵往栈顶加入一个新元素,称进栈(压栈); ⑶删除栈顶元素,称出栈(退栈、弹出); ⑷查看当前的栈顶元素,称读栈;{注意与⑶的区别}

  ⑸在使用栈的过程中,还要不断测试栈是否为空或已满,称为测试栈。

  2.栈的存储结构

  栈是一种线性表,在计算机中用向量作为栈的存储结构最为简单。因此,当用编程语言写程序时,用一维数组来建栈十分方便。例如,设一维数组STACK[1..n] 表示一个栈,其中n为栈的容量,即可存放元素的最大个数。栈的第一个元素,或称栈底元素,是存放在STACK[1]处,第二个元素存放在STACK[2]处,第i个元素存放在STACK[i]处。另外,由于栈顶元素经常变动,需要设置一个指针变量top,用来指示栈顶当前位置,栈中没有元素即栈空时,令top=0,当top=n时,表示栈满。

  如果一个栈已经为空,但用户还继续做出栈(读栈)操作,则会出现栈的“下溢”;如果一个栈已经满了,用户还继续做进栈操作,则会出现栈的“上溢”。两种情况统称为栈的溢出。

  3.对栈的几种运算的实现方法: (1)建栈

  这比较简单,只要建立一个一维数组,再把栈顶指针置为零。栈的容量根据具体的应用要求而定。比如:

  type arraytype= array[1.. n] of integer;

  var stack:arraytype;

  top:integer; 再在程序开始时,置top:=0; (2)测试栈

  测试栈顶指针的值,若top=0,则栈空;若top=n,则栈满。 (3)读栈

  若top=0,则栈空,无栈顶元素可读,出错;若top<>0,则回送栈顶元素的值STACK[top]。

  (4)进栈(push)

  将栈顶指针加1后,再把新元素送到栈顶。假设新元素x为整型,栈的最大深度为n,x和n设置为值型参。而栈和栈顶指针要设置成变量型参。

  procedure push(var stack:arraytype;var top:integer;n:integer;x:integer);

  begin if top=n

  then begin writeln(?Stack full!?); halt end else begin top:=top+1; stack[top]:= x end

  end;

  (5) 退栈(pop)

  取得栈顶元素的值后,再把栈顶指针top减1。注意都用变量型参。 procedure pop(var stack:arraytype;var 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;

  注意:由于栈本身和栈顶指针是密不可分的,所以有时我们把他们定义成一个记录来处理。如:

  type stack=record

  vec:array[1..n] of integer; {n为栈可达到的最大深度} top:integer; end;

  则以上几种运算的实现只要稍做修改即可。 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.vec[s.top]:= x end

  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.vec[s.top]; s.top:=s.top-1 end

  end;

  出栈有时也可用函数实现,如: function pop(var s:stack):integer; begin

  if s.top=0

  then begin writeln(?Stack empty!?); halt end else begin pop:=s.vec[s.top]; s.top:=s.top-1 end

  end;

  栈在计算机科学领域有着广泛的应用。比如在编译和运行计算机程序的过程中,就需要用栈进行语法检查(如检查begin和end、“(”和“)”等是否匹配)、计算表达式的值、实现过程和函数的递归调用等。下面举例说明栈在这些方面的应用。

  例1、 假设一个表达式有英文字母(小写)、运算符(+,—,*,/)和左右小(圆)括号

  构成,以“@”作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返回“YES”;否则返回“NO”。表达式长度小于255,左圆括号少于20个。

  分析:假设输入的字符串存储在c中(var c:string[255])。

  我们可以定义一个栈:var s:array[1..maxn] of char;top:integer; 用它来存放表达式中从左往右的左圆括号。

  算法的思路为:顺序(从左往右)扫描表达式的每个字符c[i],若是“(”,则让它进栈;若遇到的是“)”,则让栈顶元素出栈;当栈发生下溢或当表达式处理完毕而栈非空时,表示不匹配,返回“YES”,否则表示匹配返回“NO”。 程序代码如下: var c:string;

  function doit(c:string):boolean; var s:array[1..20] of char; top,i:integer;

  ch:char; begin top:=0; i:=1;ch:=c[i]; while ch<>'@' do begin

  if (ch='(') or (ch=')') then case ch of

  '(':begin top:=top+1;s[top]:='(' end; ')':if top>0 then top:=top-1

  else begin doit:=false;exit end; end; i:=i+1;ch:=c[i]; end;

  if top=0 then doit:=true else doit:=false; end; begin

  assign(input,'in.txt'); reset(input); readln(c); writeln(doit(c)); close(input); end. 2、背包问题

  问题:假设有n件质量分配为w1,w2,...,wn的物品和一个最多能装载总质量为T的背包,能否从这n件物品中选择若干件物品装入背包,使得被选物品的总质量恰好等于背包所能装载的最大质量,即wi1+wi2+...+wik=T。若能,则背包问题有解,否则无解。 算法思想:首先将n件物品排成一列,依次选取;若装入某件物品后,背包内物品的总质量不超过背包最大装载质量时,则装入(进栈);否则放弃这件物品的选择,选择下一件物品试探,直至装入的物品总和正好是背包的最大转载质量为止。这时我们称背包装满。 若装入若干物品的背包没有满,而且又无其他物品可以选入背包,说明已装入背包的物品中有不合格者,需从背包中取出最后装入的物品(退栈),然后在未装入的物品中挑选,重复此过程,直至装满背包(有解),或无物品可选(无解)为止。

  具体实现:设用数组weight[1..N],stack[1,N]分别存放物品重量和已经装入背包(栈)的物品序号,MaxW表示背包的最大装载量。每进栈一个物品,就从MaxW中减去该物品的质量,设i为待选物品序号,若MaxW-weight[i]>=0,则该物品可选;若MaxW-weight[i] < 0,则该物品不可选,且若i>n,则需退栈,若此时栈空,则说明无解。 (本题作为课后作业,具体程序请大家自行完成) [栈的应用举例]

  1、若已知一个栈的入栈顺序是1,2,3,…,n,其输出序列为P1,P2,P3,…,Pn,若P1是n,则Pi是( )。

  A)i B)n-1 C)n-i+1 D)不确定

  2、以下哪一个不是栈的基本运算( )。

  A)删除栈顶元素 B)删除栈底的元素 C)判断栈是否为空 D)将栈置为空栈

  3、设栈S和队列Q初始状态为空,元素e 1 ,e 2 ,e 3 ,e 4 ,e 5 ,e 6依次通过栈S,

  一个元素出栈后即进入队列Q,若出队的顺序为e 2 ,e 4 ,e 3 ,e 6 ,e 5 ,e 1 ,则栈S的容量至少应该为( )。 A)2 B)3 C)4 D)5

  4、设栈S的初始状态为空,现有5个元素组成的序列{1,2,3,4,5},对该序列在S 栈上依次进行如下操作(从序列中的1开始,出栈后不在进栈):进栈,进栈,进栈,出栈,进栈,出栈,进栈,问出栈的元素序列是:_________,栈顶指针的值为______,栈顶元素为:___________________。

  5、设栈S和队列Q初始状态为空,元素e 1 ,e 2 ,e 3 ,e 4 ,e 5 ,e 6依次通过栈S,一个元素出栈后即进入队列Q,若出队顺序为e 2 ,e 4 ,e 3 ,e 6 ,e 5 ,e 1 ,则栈S的

  容量至少应该为______________。

  6、如下图,有一个无穷大的的栈S,在栈的右边排列着1,2,3,4,5共五个车厢。其中每个车厢可以向左行走,也可以进入栈S让后面的车厢通过。现已知第一个到达出口的是3号车厢,请写出所有可能的到达出口的车厢排列总数(不必给出每种排列)。

  出口←

  ← S↓

  1 2 3 4 5

  参考答案

  1、C 2、B 3、B

  4、出栈序列为{3,4},栈顶指针值为3,栈顶元素为5 5、3 6、9
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值