第3章++栈和队列+课后习题答案.docx
- 文档编号:28584280
- 上传时间:2023-07-19
- 格式:DOCX
- 页数:17
- 大小:31.30KB
第3章++栈和队列+课后习题答案.docx
《第3章++栈和队列+课后习题答案.docx》由会员分享,可在线阅读,更多相关《第3章++栈和队列+课后习题答案.docx(17页珍藏版)》请在冰豆网上搜索。
第3章++栈和队列+课后习题答案
第3章栈和队列
习题
1.选择题
(1)若让元素1,2,3,4,5依次进栈,则出栈次序不可能出现在()种情况。
A.5,4,3,2,1B.2,1,5,4,3C.4,3,1,2,5D.2,3,5,4,1
(2)若已知一个栈的入栈序列是1,2,3,…,n,其输出序列为p1,p2,p3,…,pn,若p1=n,则pi为()。
A.iB.n-iC.n-i+1D.不确定
(3)数组Q[n]用来表示一个循环队列,f为当前队列头元素的前一位置,r为队尾元素的位置,假定队列中元素的个数小于n,计算队列中元素个数的公式为()。
A.r-fB.(n+f-r)%nC.n+r-fD.(n+r-f)%n
(4)链式栈结点为:
(data,link),top指向栈顶.若想摘除栈顶结点,并将删除结点的值保存到x中,则应执行操作()。
A.x=top->data;top=top->link;B.top=top->link;x=top->link;
C.x=top;top=top->link;D.x=top->link;
(5)设有一个递归算法如下
intfact(intn){ //n大于等于0
if(n<=0)return1;
elsereturnn*fact(n-1); }
则计算fact(n)需要调用该函数的次数为()。
A. n+1 B. n-1 C.n D.n+2
(6)栈在 ()中有所应用。
A.递归调用B.函数调用C.表达式求值D.前三个选项都有
(7)为解决计算机主机与打印机间速度不匹配问题,通常设一个打印数据缓冲区。
主机将要输出的数据依次写入该缓冲区,而打印机则依次从该缓冲区中取出数据。
该缓冲区的逻辑结构应该是()。
A.队列B.栈C.线性表D.有序表
(8)设栈S和队列Q的初始状态为空,元素e1、e2、e3、e4、e5和e6依次进入栈S,一个元素出栈后即进入Q,若6个元素出队的序列是e2、e4、e3、e6、e5和e1,则栈S的容量至少应该是( )。
A.2B.3C.4D.6
(9)在一个具有n个单元的顺序栈中,假设以地址高端作为栈底,以top作为栈顶指针,则当作进栈处理时,top的变化为( )。
A.top不变B.top=0C.top--D.top++
(10)设计一个判别表达式中左,右括号是否配对出现的算法,采用( )数据结构最佳。
A.线性表的顺序存储结构B.队列
C.线性表的链式存储结构D.栈
(11)用链接方式存储的队列,在进行删除运算时( )。
A.仅修改头指针B.仅修改尾指针
C.头、尾指针都要修改D.头、尾指针可能都要修改
(12)循环队列存储在数组A[0..m]中,则入队时的操作为( )。
A.rear=rear+1B.rear=(rear+1)%(m-1)
C.rear=(rear+1)%mD.rear=(rear+1)%(m+1)
(13)最大容量为n的循环队列,队尾指针是rear,队头是front,则队空的条件是( )。
A.(rear+1)%n==frontB.rear==front
C.rear+1==frontD.(rear-l)%n==front
(14)栈和队列的共同点是( )。
A.都是先进先出B.都是先进后出
C.只允许在端点处插入和删除元素D.没有共同点
(15)一个递归算法必须包括( )。
A.递归部分B.终止条件和递归部分
C.迭代部分D.终止条件和迭代部分
(2)回文是指正读反读均相同的字符序列,如“abba”和“abdba”均是回文,但“good”不是回文。
试写一个算法判定给定的字符向量是否为回文。
(提示:
将一半字符入栈)
根据提示,算法可设计为:
//以下为顺序栈的存储结构定义
#defineStackSize100//假定预分配的栈空间最多为100个元素
typedefcharDataType;//假定栈元素的数据类型为字符
typedefstruct{
DataTypedata[StackSize];
inttop;
}SeqStack;
intIsHuiwen(char*t)
{//判断t字符向量是否为回文,若是,返回1,否则返回0
SeqStacks;
inti,len;
chartemp;
InitStack(&s);
len=strlen(t);//求向量长度
for(i=0;i Push(&s,t[i]); while(! EmptyStack(&s)) {//每弹出一个字符与相应字符比较 temp=Pop(&s); if(temp! =S[i]) return0;//不等则返回0 elsei++; } return1;//比较完毕均相等则返回1 } (3)设从键盘输入一整数的序列: a1,a2,a3,…,an,试编写算法实现: 用栈结构存储输入的整数,当ai≠-1时,将ai进栈;当ai=-1时,输出栈顶整数并出栈。 算法应对异常情况(入栈满等)给出相应的信息。 #definemaxsize栈空间容量 voidInOutS(ints[maxsize]) //s是元素为整数的栈,本算法进行入栈和退栈操作。 {inttop=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);}elses[++top]=x;//x入栈。 else//读入的整数等于-1时退栈。 {if(top==0){printf(“栈空\n”);exit(0);}elseprintf(“出栈元素是%d\n”,s[top--]);}} }//算法结束。 (4)从键盘上输入一个后缀表达式,试编写算法计算表达式的值。 规定: 逆波兰表达式的长度不超过一行,以$符作为输入结束,操作数之间用空格分隔,操作符只可能有+、-、*、/四种运算。 例如: 23434+2*$。 [题目分析]逆波兰表达式(即后缀表达式)求值规则如下: 设立运算数栈OPND,对表达式从左到右扫描(读入),当表达式中扫描到数时,压入OPND栈。 当扫描到运算符时,从OPND退出两个数,进行相应运算,结果再压入OPND栈。 这个过程一直进行到读出表达式结束符$,这时OPND栈中只有一个数,就是结果。 floatexpr() //从键盘输入逆波兰表达式,以‘$’表示输入结束,本算法求逆波兰式表达式的值。 {floatOPND[30];//OPND是操作数栈。 init(OPND);//两栈初始化。 floatnum=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;//数压入栈,下个数初始化 casex=‘’: break;//遇空格,继续读下一个字符。 casex=‘+’: push(OPND,pop(OPND)+pop(OPND));break; casex=‘-’: x1=pop(OPND);x2=pop(OPND);push(OPND,x2-x1);break; casex=‘*’: push(OPND,pop(OPND)*pop(OPND));break; casex=‘/’: 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语句。 (5)假设以I和O分别表示入栈和出栈操作。 栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和O组成的序列,称可以操作的序列为合法序列,否则称为非法序列。 下面所示的序列中哪些是合法的? A.IOIIOIOOB.IOOIOIIOC.IIIOIOIOD.IIIOOIOO 通过对 的分析,写出一个算法,判定所给的操作序列是否合法。 若合法,返回true,否则返回false(假定被判定的操作序列已存入一维数组中)。 A和D是合法序列,B和C是非法序列。 设被判定的操作序列已存入一维数组A中。 intJudge(charA[]) //判断字符数组A中的输入输出序列是否是合法序列。 如是,返回true,否则返回false。 {i=0;//i为下标。 j=k=0;//j和k分别为I和字母O的的个数。 while(A[i]! =‘\0’)//当未到字符数组尾就作。 {switch(A[i]) {case‘I’: j++;break;//入栈次数增1。 case‘O’: k++;if(k>j){printf(“序列非法\n”);exit(0);} } i++;//不论A[i]是‘I’或‘O’,指针i均后移。 } if(j! =k){printf(“序列非法\n”);return(false);} else{printf(“序列合法\n”);return(true);} }//算法结束。 [算法讨论]在入栈出栈序列(即由‘I’和‘O’组成的字符串)的任一位置,入栈次数(‘I’的个数)都必须大于等于出栈次数(即‘O’的个数),否则视作非法序列,立即给出信息,退出算法。 整个序列(即读到字符数组中字符串的结束标记‘\0’),入栈次数必须等于出栈次数(题目中要求栈的初态和终态都为空),否则视为非法序列。 (6)假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素站点(注意不设头指针),试编写相应的置空队、判队空、入队和出队等算法。 算法如下: //先定义链队结构: typedefstructqueuenode{ Datatypedata; structqueuenode*next; }QueueNode;//以上是结点类型的定义 typedefstruct{ queuenode*rear; }LinkQueue;//只设一个指向队尾元素的指针 (1)置空队 voidInitQueue(LinkQueue*Q) {//置空队: 就是使头结点成为队尾元素 QueueNode*s; Q->rear=Q->rear->next;//将队尾指针指向头结点 while(Q->rear! =Q->rear->next)//当队列非空,将队中元素逐个出队 {s=Q->rear->next; Q->rear->next=s->next; free(s); }//回收结点空间 } (2)判队空 intEmptyQueue(LinkQueue*Q) {//判队空 //当头结点的next指针指向自己时为空队 returnQ->rear->next->next==Q->rear->next; } (3)入队 voidEnQueue(LinkQueue*Q,Datatypex) {//入队 //也就是在尾结点处插入元素 QueueNode*p=(QueueNode*)malloc(sizeof(QueueNode));//申请新结点 p->data=x;p->next=Q->rear->next;//初始化新结点并链入 Q-rear->next=p; Q->rear=p;//将尾指针移至新结点 } (4)出队 DatatypeDeQueue(LinkQueue*Q) {//出队,把头结点之后的元素摘下 Datatypet; QueueNode*p; if(EmptyQueue(Q)) Error("Queueunderflow"); p=Q->rear->next->next;//p指向将要摘下的结点 x=p->data;//保存结点中数据 if(p==Q->rear) {//当队列中只有一个结点时,p结点出队后,要将队尾指针指向头结点 Q->rear=Q->rear->next;Q->rear->next=p->next;} else Q->rear->next->next=p->next;//摘下结点p free(p);//释放被删结点 returnx; } (7)假设以数组Q[m]存放循环队列中的元素,同时设置一个标志tag,以tag==0和tag==1来区别在队头指针(front)和队尾指针(rear)相等时,队列状态为“空”还是“满”。 试编写与此结构相应的插入(enqueue)和删除(dlqueue)算法。 【解答】 循环队列类定义 #include template public: Queue(int=10); ~Queue(){delete[]Q;} voidEnQueue(Type&item); TypeDeQueue(); TypeGetFront(); voidMakeEmpty(){front=rear=tag=0;}//置空队列 intIsEmpty()const{returnfront==rear&&tag==0;}//判队列空否 intIsFull()const{returnfront==rear&&tag==1;}//判队列满否 private: intrear,front,tag;//队尾指针、队头指针和队满标志 Type*Q;//存放队列元素的数组 intm;//队列最大可容纳元素个数 } 构造函数 template Queue : Queue(intsz): rear(0),front(0),tag(0),m(sz){ //建立一个最大具有m个元素的空队列。 Q=newType[m];//创建队列空间 assert(Q! =0);//断言: 动态存储分配成功与否 } 插入函数 template voidQueue : EnQueue(Type&item){ assert(! IsFull());//判队列是否不满,满则出错处理 rear=(rear+1)%m;//队尾位置进1,队尾指针指示实际队尾位置 Q[rear]=item;//进队列 tag=1;//标志改1,表示队列不空 } 删除函数 template TypeQueue : DeQueue(){ assert(! IsEmpty());//判断队列是否不空,空则出错处理 front=(front+1)%m;//队头位置进1,队头指针指示实际队头的前一位置 tag=0;//标志改0,表示栈不满 returnQ[front];//返回原队头元素的值 } 读取队头元素函数 template TypeQueue : GetFront(){ assert(! IsEmpty());//判断队列是否不空,空则出错处理 returnQ[(front+1)%m];//返回队头元素的值 } (8)如果允许在循环队列的两端都可以进行插入和删除操作。 要求: 写出循环队列的类型定义; 写出“从队尾删除”和“从队头插入”的算法。 [题目分析]用一维数组v[0..M-1]实现循环队列,其中M是队列长度。 设队头指针front和队尾指针rear,约定front指向队头元素的前一位置,rear指向队尾元素。 定义front=rear时为队空,(rear+1)%m=front为队满。 约定队头端入队向下标小的方向发展,队尾端入队向下标大的方向发展。 (1)#defineM队列可能达到的最大长度 typedefstruct {elemtpdata[M]; intfront,rear; }cycqueue; (2)elemtpdelqueue(cycqueueQ) //Q是如上定义的循环队列,本算法实现从队尾删除,若删除成功,返回被删除元素,否则给出出错信息。 {if(Q.front==Q.rear){printf(“队列空”);exit(0);} Q.rear=(Q.rear-1+M)%M;//修改队尾指针。 return(Q.data[(Q.rear+1+M)%M]);//返回出队元素。 }//从队尾删除算法结束 voidenqueue(cycqueueQ,elemtpx) //Q是顺序存储的循环队列,本算法实现“从队头插入”元素x。 {if(Q.rear==(Q.front-1+M)%M){printf(“队满”;exit(0);) Q.data[Q.front]=x;//x入队列 Q.front=(Q.front-1+M)%M;//修改队头指针。 }//结束从队头插入算法。 (9)已知Ackermann函数定义如下: 写出计算Ack(m,n)的递归算法,并根据此算法给出出Ack(2,1)的计算过程。 写出计算Ack(m,n)的非递归算法。 intAck(intm,n) {if(m==0)return(n+1); elseif(m! =0&&n==0)return(Ack(m-1,1)); elsereturn(Ack(m-1,Ack(m,m-1)); }//算法结束 (1)Ack(2,1)的计算过程 Ack(2,1)=Ack(1,Ack(2,0))//因m<>0,n<>0而得 =Ack(1,Ack(1,1))//因m<>0,n=0而得 =Ack(1,Ack(0,Ack(1,0)))//因m<>0,n<>0而得 =Ack(1,Ack(0,Ack(0,1)))//因m<>0,n=0而得 =Ack(1,Ack(0,2))//因m=0而得 =Ack(1,3)//因m=0而得 =Ack(0,Ack(1,2))//因m<>0,n<>0而得 =Ack(0,Ack(0,Ack(1,1)))//因m<>0,n<>0而得 =Ack(0,Ack(0,Ack(0,Ack(1,0))))//因m<>0,n<>0而得 =Ack(0,Ack(0,Ack(0,Ack(0,1))))//因m<>0,n=0而得 =Ack(0,Ack(0,Ack(0,2)))//因m=0而得 =Ack(0,Ack(0,3))//因m=0而得 =Ack(0,4)//因n=0而得 =5//因n=0而得 (2)intAckerman(intm,intn) {intakm[M][N];inti,j; for(j=0;j for(i=1;i {akm[i][0]=akm[i-1][1]; for(j=1;j akm[i][j]=akm[i-1][akm[i][j-1]]; } return(akm[m][n]); }//算法结束 (10)已知f为单链表的表头指针,链表中存储的都是整型数据,试写出实现下列运算的递归算法: 求链表中的最大整数; 求链表的结点个数; 求所有整数的平均值。 #include classList; classListNode{//链表结点类
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 队列 课后 习题 答案
![提示](https://static.bdocx.com/images/bang_tan.gif)