【www.chawenzhang.com--知识文库】

数据结构栈和队列练习题及答案   一 选择题 1. 对于栈操作数据的原则是(B )。 A. 先进先出    B.后进先出      C.后进后出     D. 不分顺序 2.一个栈的输入序列为123…n,若输出序列的第一个元素是n,输出第i(1<=i<=n)个元素是( B )。 A.不确定       B.n-i+1       C. i     D. n-i      3. 若一个栈的输入序列为1,2,3,…,n,输出序列的第一个元素是i,则第j个输出元素是(D )。 A.i-j-1       B.i-j     C.j-i+1       D. 不确定的 4. 若已知一个栈的入栈序列是1,2,3,…,n,其输出序列为p1,p2,p3,…,pN,若pN是n,则pi是( D )。 A. i     B.n-i     C.n-i+1    D. 不确定 5. 有六个元素6,5,4,3,2,1 的顺序进栈,问下列哪一个不是合法的出栈序列?( C )。 A. 5 4 3 6 1 2     B. 4 5 3 1 2 6     C. 3 4 6 5 2 1     D. 2 3 4 1 5 6  6. 设栈的输入序列是1,2,3,4,则(D )不可能是其出栈序列。 A. 1,2,4,3,      B. 2,1,3,4,    C. 1,4,3,2,  D. 4,3,1,2,     E. 3,2,1,4, 7. 一个栈的输入序列为1 2 3 4 5,则下列序列中不可能是栈的输出序列的是( B )。 A. 2 3 4 1 5      B. 5 4 1 3 2    C. 2 3 1 4 5      D. 1 5 4 3 2 8. 设一个栈的输入序列是 1,2,3,4,5,则下列序列中,是栈的合法输出序列的是( D )。 A. 5 1 2 3 4      B. 4 5 1 3 2     C. 4 3 1 2 5      D. 3 2 1 5 4 9. 某堆栈的输入序列为a, b,c ,d,下面的四个序列中,不可能是它的输出序列的是( D )。 A. a,c,b,d     B. b, c,d,a     C. c, d,b, a     D. d, c,a,b 10. 设abcdef以所给的次序进栈,若在进栈操作时,允许退栈操作,则下面得不到的序列为( D )。 A.fedcba    B. bcafed     C. dcefba    D. cabdef 11. 设有三个元素X,Y,Z顺序进栈(进的过程中允许出栈),下列得不到的出栈排列是( C )。 A.XYZ       B. YZX       C. ZXY       D. ZYX 12. 用链接方式存储的队列,在进行删除运算时(D )。 A. 仅修改头指针      B. 仅修改尾指针       C. 头、尾指针都要修改       D. 头、尾指针可能都要修改 13. 用不带头结点的单链表存储队列时,其队头指针指向队头结点,其队尾指针指向队尾结点,则在进行删除操作时( D )。 A.仅修改队头指针     B. 仅修改队尾指针       C. 队头、队尾指针都要修改   D. 队头,队尾指针都可能要修改 14. 递归过程或函数调用时,处理参数及返回地址,要用一种称为(C )的数据结构。 A.队列      B.多维数组     C.栈       D. 线性表     二、判断题 1. 消除递归不一定需要使用栈,此说法(√ ) 2. 栈是实现过程和函数等子程序所必需的结构。(√ ) 3. 两个栈共用静态存储空间,对头使用也存在空间溢出问题。(√ ) 4.两个栈共享一片连续内存空间时,为提高内存利用率,减少溢出机会,应把两个栈的栈底分别设在这片内存空间的两端。(√ ) 5. 即使对不含相同元素的同一输入序列进行两组不同的合法的入栈和出栈组合操作,所得的输出序列也一定相同。(× ) 6. 栈与队列是一种特殊操作的线性表。(√ ) 7. 若输入序列为1,2,3,4,5,6,则通过一个栈可以输出序列3,2,5,6,4,1. (√ ) 8. 栈和队列都是限制存取点的线性结构。( √ ) 9.若输入序列为1,2,3,4,5,6,则通过一个栈可以输出序列1,5,4,6,2,3。(× ) 10. 任何一个递归过程都可以转换成非递归过程。(√  ) 11. 只有那种使用了局部变量的递归过程在转换成非递归过程时才必须使用栈。(× ) 12. 队列是一种插入与删除操作分别在表的两端进行的线性表,是一种先进后出型结构。(× ) 13. 通常使用队列来处理函数或过程的调用。(× ) 14. 队列逻辑上是一个下端和上端既能增加又能减少的线性表。(√ ) 15. 循环队列通常用指针来实现队列的头尾相接。(× ) 16. 循环队列也存在空间溢出问题。(√ ) 17. 队列和栈都是运算受限的线性表,只允许在表的两端进行运算。(× ) 18. 栈和队列都是线性表,只是在插入和删除时受到了一些限制。(√ ) 19. 栈和队列的存储方式,既可以是顺序方式,又可以是链式方式。(√ )   三、填空  1.栈是操作受限(或限定仅在表尾进行插入和删除操作)的线性表,其运算遵循后进先出的原则。 2.栈 是限定仅在表尾进行插入或删除操作的线性表。 3. 一个栈的输入序列是:1,2,3则不可能的栈输出序列是3 1 2。 4.两个栈共享空间时栈满的条件两栈顶指针值相减的绝对值为1(或两栈顶指针相邻)。。 5.在作进栈运算时应先判别栈是否满;在作退栈运算时应先判别栈是否空;当栈中元素为n个,作进栈运算时发生上溢,则说明该栈的最大容量为n。为了增加内存空间的利用率和减少溢出的可能性,由两个栈共享一片连续的空间时,应将两栈的栈底 分别设在内存空间的两端,这样只有当两栈顶指针相邻(即值之差的绝对值为1)时才产生溢出。 6. 多个栈共存时,最好用链式存储结构作为存储结构。 7.用S表示入栈操作,X表示出栈操作,若元素入栈的顺序为1234,为了得到1342出栈顺序,相应的S和X的操作串为S×SS×S×× 。 8. 循环队列的引入,目的是为了克服假溢出时大量移动数据元素。 9.队列又称作先进先出表。 10. 已知链队列的头尾指针分别是f和r,则将值x入队的操作序列是s=(LinkedList)malloc(sizeof(LNode)); s->data=x;s->next=r->next;r->next=s;r=s;。 11.区分循环队列的满与空,只有两种方法,它们是牺牲一个存储单元和设标记。   四、应用题 1. 名词解释:栈。 答:栈是只准在一端进行插入和删除操作的线性表,允许插入和删除的一端叫栈顶,另一端叫栈底。最后插入的元素最先删除,故栈也称后进先出(LIFO)表。   2. 名词解释:队列 答:队列是允许在一端插入而在另一端删除的线性表,允许插入的一端叫队尾,允许删除的一端叫队头。最先插入队的元素最先离开(删除),故队列也常称先进先出(FIFO)表。    3. 什么是循环队列? 答:用常规意义下顺序存储结构的一维数组表示队列,由于队列的性质(队尾插入和队头删除),容易造成“假溢出”现象,即队尾已到达一维数组的高下标,不能再插入,然而队中元素个数小于队列的长度(容量)。循环队列是解决“假溢出”的一种方法。通常把一维数组看成首尾相接。在循环队列下,通常采用“牺牲一个存储单元”或“作标记”的方法解决“队满”和“队空”的判定问题。    4. 假设以S和X分别表示入栈和出栈操作,则对初态和终态均为空的栈操作可由S和X组成的序列表示(如SXSX)。 (1)试指出判别给定序列是否合法的一般规则。 答:通常有两条规则。第一是给定序列中S的个数和X的个数相等;第二是从给定序列的开始,到给定序列中的任一位置,S的个数要大于或等于X的个数。     (2)两个不同合法序列(对同一输入序列)能否得到相同的输出元素序列?如能得到,请举列说明。 答:可以得到相同的输出元素序列。例如,输入元素为A,B,C,则两个输入的合法序列ABC和BAC均可得到输出元素序列ABC。对于合法序列ABC,我们使用本题约定的S×S×S×操作序列;对于合法序列BAC,我们使用SS××S×操作序列。     5. 有5 个元素,其入栈次序为:A,B,C,D,E,在各种可能的出栈次序中,以元素C,D最先出栈(即C第一个且D第二个出栈)的次序有哪几个? 答:三个:CDEBA,CDBEA,CDBAE    6. 如果输入序列为1 2 3 4 5 6,试问能否通过栈结构得到以下两个序列:4 3 5 6 1 2和1 3 5 4 2 6;请说明为什么不能或如何才能得到。 答:输入序列为123456,不能得出435612,其理由是,输出序列最后两元素是12,前面4个元素(4356)得到后,栈中元素剩12,且2在栈顶,不可能栈底元素1在栈顶元素2之前出栈。     得到135426的过程如下:1入栈并出栈,得到部分输出序列1;然后2和3入栈,3出栈,部分输出序列变为:13;接着4和5入栈,5,4和2依次出栈,部分输出序列变为13542;最后6入栈并退栈,得最终结果135426。    7. 若元素的进栈序列为:A、B、C、D、E,运用栈操作,能否得到出栈序列B、C、A、E、D和D、B、A、C、E?为什么? 答: 能得到出栈序列B、C、A、E、D,不能得到出栈序列D、B、A、C、E。其理由为:若出栈序列以D开头,说明在D之前的入栈元素是A、B和C,三个元素中C是栈顶元素,B和A不可能早于C出栈,故不可能得到D、B、A、C、E出栈序列。    8. 设输入序列为a,b,c,d,试写出借助一个栈可得到的两个输出序列和两个不能得到的输出序列。 答:借助栈结构,n个入栈元素可得到1/(n+1)((2n)!/(n!*n!))种出栈序列。本题4个元素,可有14种出栈序列,abcd和dcba就是其中两种。但dabc和adbc是不可能得到的两种。    9. 设输入序列为2,3,4,5,6,利用一个栈能得到序列2,5,3,4,6吗?栈可以用单链表实现吗? 答:不能得到序列2,5,3,4,6。栈可以用单链表实现,这就是链栈。由于栈只在栈顶操作,所以链栈通常不设头结点。    五、算法设计题 1. 设从键盘输入一整数的序列:a1, a2, a3,…,an,试编写算法实现:用栈结构存储输入的整数,当ai≠-1时,将ai进栈;当ai=-1时,输出栈顶整数并出栈。算法应对异常情况(入栈满等)给出相应的信息。 答:#define maxsize 栈空间容量      void InOutS(int s[maxsize])     //s是元素为整数的栈,本算法进行入栈和退栈操作。         {int top=0; //top为栈顶指针,定义top=0时为栈空。          for(i=1; i<=n; i++) //n个整数序列作处理。         {scanf(“%d”,&x); //从键盘读入整数序列。          if(x!=-1) // 读入的整数不等于-1时入栈。         if(top==maxsize-1){printf(“栈满\n”);exit(0);}else s[++top]=x; //x入栈。         else //读入的整数等于-1时退栈。          {if(top==0){printf(“栈空\n”);exit(0);} else printf(“出栈元素是%d\n”,s[top--]);}}      }//算法结束。    2. 设表达式以字符形式已存入数组E[n]中,‘#’为表达式的结束符,试写出判断表达式中括号(‘(’和‘)’)是否配对的C语言描述算法:EXYX(E); (注:算法中可调用栈操作的基本算法。) 答:[题目分析]判断表达式中括号是否匹配,可通过栈,简单说是左括号时进栈,右括号时退栈。退栈时,若栈顶元素是左括号,则新读入的右括号与栈顶左括号就可消去。如此下去,输入表达式结束时,栈为空则正确,否则括号不匹配。      int EXYX(char E[],int n)      //E[]是有n字符的字符数组,存放字符串表达式,以‘#’结束。本算法判断表达式中圆括号是否匹配。      {char s[30]; //s是一维数组,容量足够大,用作存放括号的栈。      int top=0; //top用作栈顶指针。      s[top]= ‘#’; //‘#’先入栈,用于和表达式结束符号‘#’匹配。      int i=0; //字符数组E的工作指针。      while(E[i]!= ‘#’) //逐字符处理字符表达式的数组。           switch(E[i])      {case‘(’: s[++top]=‘(’; i++ ; break ;      case‘)’: if(s[top]==‘(’{top--; i++; break;}           else{printf(“括号不配对”);exit(0);}           case‘#’: if(s[top]==‘#’){printf(“括号配对\n”);return (1);}           else {printf(“ 括号不配对\n”);return (0);} //括号不配对           default : i++; //读入其它字符,不作处理。           }      }//算法结束。      [算法讨论]本题是用栈判断括号匹配的特例:只检查圆括号的配对。一般情况是检查花括号(‘{’,‘}’)、方括号(‘[’,‘]’)和圆括号(‘(’,‘)’)的配对问题。编写算法中如遇左括号(‘{’,‘[’,或‘(’)就压入栈中,如遇右括号(‘}’,‘]’,或‘)’),则与栈顶元素比较,如是与其配对的括号(左花括号,左方括号或左圆括号),则弹出栈顶元素;否则,就结论括号不配对。在读入表达式结束符‘#’时,栈中若应只剩‘#’,表示括号全部配对成功;否则表示括号不匹配。      另外,由于本题只是检查括号是否匹配,故对从表达式中读入的不是括号的那些字符,一律未作处理。再有,假设栈容量足够大,因此入栈时未判断溢出。    3. 从键盘上输入一个逆波兰表达式,用伪码写出其求值程序。规定:逆波兰表达式的长度不超过一行,以$符作为输入结束,操作数之间用空格分隔,操作符只可能有+、-、*、/四种运算。例如:234 34+2*$ 答:[题目分析]逆波兰表达式(即后缀表达式)求值规则如下:设立运算数栈OPND,对表达式从左到右扫描(读入),当表达式中扫描到数时,压入OPND栈。当扫描到运算符时,从OPND退出两个数,进行相应运算,结果再压入OPND栈。这个过程一直进行到读出表达式结束符$,这时OPND栈中只有一个数,就是结果。      float expr( )      //从键盘输入逆波兰表达式,以‘$’表示输入结束,本算法求逆波兰式表达式的值。      {float OPND[30]; // OPND是操作数栈。       init(OPND); //两栈初始化。      float num=0.0; //数字初始化。      scanf (“%c”,&x);//x是字符型变量。      while(x!=’$’)      {switch           {case‘0’<=x<=’9’:while((x>=’0’&&x<=’9’)||x==’.’) //拼数                if(x!=’.’) //处理整数      {num=num*10+(ord(x)-ord(‘0’)); scanf(“%c”,&x);}                else //处理小数部分。                {scale=10.0; scanf(“%c”,&x);                while(x>=’0’&&x<=’9’)                {num=num+(ord(x)-ord(‘0’)/scale;                scale=scale*10; scanf(“%c”,&x); }                }//else                push(OPND,num); num=0.0;//数压入栈,下个数初始化      case x=‘ ’:break; //遇空格,继续读下一个字符。      case x=‘+’:push(OPND,pop(OPND)+pop(OPND));break;      case x=‘-’:x1=pop(OPND);x2=pop(OPND);push(OPND,x2-x1);break;      case x=‘*’:push(OPND,pop(OPND)*pop(OPND));break;      case x=‘/’:x1=pop(OPND);x2=pop(OPND);push(OPND,x2/x1);break;      default: //其它符号不作处理。      }//结束switch      scanf(“%c”,&x);//读入表达式中下一个字符。      }//结束while(x!=‘$’)      printf(“后缀表达式的值为%f”,pop(OPND));      }//算法结束。      [算法讨论]假设输入的后缀表达式是正确的,未作错误检查。算法中拼数部分是核心。若遇到大于等于‘0’且小于等于‘9’的字符,认为是数。这种字符的序号减去字符‘0’的序号得出数。对于整数,每读入一个数字字符,前面得到的部分数要乘上10再加新读入的数得到新的部分数。当读到小数点,认为数的整数部分已完,要接着处理小数部分。小数部分的数要除以10(或10的幂数)变成十分位,百分位,千分位数等等,与前面部分数相加。在拼数过程中,若遇非数字字符,表示数已拼完,将数压入栈中,并且将变量num恢复为0,准备下一个数。这时对新读入的字符进入‘+’、‘-’、‘*’、‘/’及空格的判断,因此在结束处理数字字符的case后,不能加入break语句。 

本文来源:https://www.chawenzhang.com/fanwen/174929/