第3章                    栈和队列
   
一、基础知识题
3.1  有五个数依次进栈:1,2,3,4,5。在各种出栈的序列中,以3,4先出的序列有哪几个。(3在4之前出栈)。
【解答】34215  34251  34521
3.2  铁路进行列车调度时,常把站台设计成栈式结构,若进站的六辆列车顺序为:1,2,3,4,5,6, 那么是否能够得到435612, 325641, 154623和135426的出站序列,如果不能,说明为什么不能; 如果能, 说明如何得到(即写出"进栈"或"出栈"的序列)。
【解答】输入序列为123456,不能得出435612和154623。不能得到435612的理由是,输出序列最后两元素是12,前面4个元素(4356)得到后,栈中元素剩12,且2在栈顶,不可能让栈底元素1在栈顶元素2之前出栈。不能得到154623的理由类似,当栈中元素只剩23,且3在栈顶,2不可能先于3出栈。
得到325641的过程如下:1 2 3顺序入栈,32出栈,得到部分输出序列32;然后45入栈,5出栈,部分输出序列变为325;接着6入栈并退栈,部分输出序列变为3256;最后41退栈,得最终结果325641。
  得到135426的过程如下:1入栈并出栈,得到部分输出序列1;然后2和3入栈,3出栈,部分输出序列变为13;接着4和5入栈,5,4和2依次出栈,部分输出序列变为13542;最后6入栈并退栈,得最终结果135426。
3.3  若用一个大小为6的数组来实现循环队列,且当前rear和front的值分别为0和3,当从队列中删除一个元素,再加入两个元素后,rear和front的值分别为多少?
【解答】2 4
3.4  设栈S和队列Q的初始状态为空,元素e1,e2,e3,e4,e5和e6依次通过栈S,一个元素出栈后即进队列Q,若6个元素出队的序列是e3,e5,e4,e6,e2,e1,则栈S的容量至少应该是多少?
【解答】 4
3.5  循环队列的优点是什么,如何判断“空”和“满”。
【解答】循环队列解决了常规用0--m-1的数组表示队列时出现的“假溢出”(即队列未满但不能入队)。在循环队列中我们仍用队头指针等于队尾指针表示队空,而用牺牲一个单元的办法表示队满,即当队尾指针加1(求模)等于队头指针时,表示队列满。也有通过设标记以及用一个队头或队尾指针加上队中元素个数来区分队列的“空”和“满”的。
3.6  设长度为n的链队列用单循环链表表示,若只设头指针,则入队和出队的时间如何?若只设尾指针呢?
【解答】若只设头指针,则入队的时间为O(n),出队的时间为O(1)。若只设尾指针,则入队和出队的时间均为O(1)。
3.7  指出下面程序段的功能是什么?
(1)  void demo1(SeqStack S)
{int i,arr[64],n=0;
whilec语言程序分析题及答案(!StackEmpty(S)) arr[n++]=Pop(S);
for(i=0;i<n;i++) Push(S,arr[i]);
}
【解答】程序段的功能是实现了栈中元素的逆置。
(2)  void demo2(SeqStack S,int m)∥设栈中元素类型为int型
{int x;SeqStack T;
StackInit(T);
while(!StackEmpty(S))
if((x=Pop(S)!=m) Push(T,x);
while(!(StackEmpty(T)) {x=Pop(T); Push(S,x);}
}
【解答】程序段的功能是删除了栈中值为m的元素。
(3)  void demo3(SeQueue Q,int m)∥设队列中元素类型为int型
{int x;SeqStack S;
StackInit(S);
while(!QueueEmpty(Q)){x=QueueOut(Q); Push(S,x);}
while(!StackEmpty(S)){x=Pop(s); QueueIn(Q,x);}
}
【解答】程序段的功能是实现了队列中元素的逆置。
3.8  试将下列递推过程改写为递归过程。
void ditui(int n)
{i=n;
        while(i>1) printf(i--);
}
【解答】void digui(int n)
{if(n>1){printf(n);
                digui(n-1);
                }
}
3.9  写出下列中缀表达式的后缀表达式:
      (1)A*B*C  (2)(A+B)*C-D    (3)A*B+C/(D-E) (4)(A+B)*D+E/(F+A*D)+C
【解答】(1)ABC** 
(2)AB+C*D-
(3)AB*CDE-/+   
(4)AB+D*EFAD*+/+C+
3.10              选择题:循环队列存储在数组]中,则入队时的操作为(  )。
  A. rear=rear+1            B. rear=(rear+1) % (m-1)
C. rear=(rear+1) % m      D. rear=(rear+1) % (m+1)
【解答】D
3.11 选择题:4个园盘的Hahoi塔,总的移动次数为(  )。
A.7        B. 8        C.15        D.16
【解答】C
3.12选择题:允许对队列进行的操作有(  )。
A. 对队列中的元素排序                      B. 取出最近进队的元素
C. 在队头元素之前插入元素                  D. 删除队头元素
【解答】D
二、算法设计题
3.13 利用栈的基本操作,编写求栈中元素个数的算法。
【题目分析】 将栈值元素出栈,出栈时计数,直至栈空。
【算法】 int StackLength(Stack S)
          {//求栈中元素个数
          int n=0;
          while(!StackEmpty(S)
              {n++; Pop(S);
              }
          return n;
          }
算法讨论:若要求统计完元素个数后,不能破坏原来栈,则在计数时,将原栈导入另一临时栈,计数完毕,再将临时栈倒入原栈中。
        int StackLength(Stack S)
          {//求栈中元素个数
          int n=0;
Stack T;
StackInit(T); //初始化临时栈T
          while(!StackEmpty(S)
              {n++; Push(T,Pop(S));
              }
while(!StackEmpty(T)
              {Push(S,Pop(T));
              }
          return n;
          }
3.14 双向栈S是在一个数组空间V[m]内实现的两个栈,栈底分别处于数组空间的两端。试为此双向栈设计栈初始化Init(S)、入栈Push(S,i,x)、出栈Pop(S,i)算法,其中i为0或1,用以指示栈号。
[题目分析]两栈共享向量空间,将两栈栈底设在向量两端,初始时,s1栈顶指针为-1,s2栈顶为m。两栈顶指针相邻时为栈满。两栈顶相向、迎面增长,栈顶指针指向栈顶元素。
#define ElemType int     ∥假设元素类型为整型
typedef struct 
{ElemType V[m];    ∥栈空间
int top[2];      ∥top为两个栈顶指针
}stk;
stk S;            ∥S是如上定义的结构类型变量,为全局变量
(1)  栈初始化
int Init()
  {S.top[0]=-1;
  S.top[1]=m;
  return 1;  //初始化成功
}
(2)  入栈操作:
int push(stk S ,int i,int x)
∥i为栈号,i=0表示左栈,i=1为右栈,x是入栈元素。入栈成功返回1,否则返回0
{if(i<0||i>1){printf(“栈号输入不对\n”);exit(0);}
if(S.top[1]-S.top[0]==1) {printf(“栈已满\n”);return(0);}
switch(i)
{case 0: S.V[++S.top[0]]=x; return(1); break;
case 1: S.V[--S.top[1]]=x; return(1);
}
}∥push
(3)  退栈操作
      ElemType pop(stk S,int i)
      ∥退栈。i代表栈号,i=0时为左栈,i=1时为右栈。退栈成功返回退栈元素
∥否则返回-1
      {if(i<0 || i>1){printf(“栈号输入错误\n”);exit(0);}
        switch(i)
        {case 0: if(S.top[0]==-1) {printf(“栈空\n”);return(-1);}
                  else return(S.p[0]--]);
          case 1: if(S.top[1]==m {printf(“栈空\n”); return(-1);}
                  else return(S.p[1]++]);
      }∥switch      }∥算法结束
(4)  判断栈空
int Empty();
{return (S.top[0]==-1 && S.top[1]==m);
}
  [算法讨论] 请注意算法中两栈入栈和退栈时的栈顶指针的计算。s1(左栈)是通常意义下的栈,而s2(右栈)入栈操作时,其栈顶指针左移(减1),退栈时,栈顶指针右移(加1)。