算法与数据结构C语言版课后习题答案机械工业出版社第34章 习题参考答案.docx
- 文档编号:7039542
- 上传时间:2023-01-16
- 格式:DOCX
- 页数:28
- 大小:34.71KB
算法与数据结构C语言版课后习题答案机械工业出版社第34章 习题参考答案.docx
《算法与数据结构C语言版课后习题答案机械工业出版社第34章 习题参考答案.docx》由会员分享,可在线阅读,更多相关《算法与数据结构C语言版课后习题答案机械工业出版社第34章 习题参考答案.docx(28页珍藏版)》请在冰豆网上搜索。
算法与数据结构C语言版课后习题答案机械工业出版社第34章习题参考答案
第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的过程如下:
123顺序入栈,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) voiddemo1(SeqStackS)
{inti,arr[64],n=0;
while(!
StackEmpty(S))arr[n++]=Pop(S);
for(i=0;i } 【解答】程序段的功能是实现了栈中元素的逆置。 (2) voiddemo2(SeqStackS,intm)∥设栈中元素类型为int型 {intx;SeqStackT; StackInit(T); while(! StackEmpty(S)) if((x=Pop(S)! =m)Push(T,x); while(! (StackEmpty(T)){x=Pop(T);Push(S,x);} } 【解答】程序段的功能是删除了栈中值为m的元素。 (3) voiddemo3(SeQueueQ,intm)∥设队列中元素类型为int型 {intx;SeqStackS; StackInit(S); while(! QueueEmpty(Q)){x=QueueOut(Q);Push(S,x);} while(! StackEmpty(S)){x=Pop(s);QueueIn(Q,x);} } 【解答】程序段的功能是实现了队列中元素的逆置。 3.8 试将下列递推过程改写为递归过程。 voidditui(intn) {i=n; while(i>1)printf(i--); } 【解答】voiddigui(intn) {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[0..m]中,则入队时的操作为()。 A.rear=rear+1B.rear=(rear+1)%(m-1) C.rear=(rear+1)%mD.rear=(rear+1)%(m+1) 【解答】D 3.11选择题: 4个园盘的Hahoi塔,总的移动次数为()。 A.7B.8C.15D.16 【解答】C 3.12选择题: 允许对队列进行的操作有()。 A.对队列中的元素排序B.取出最近进队的元素 C.在队头元素之前插入元素D.删除队头元素 【解答】D 二、算法设计题 3.13利用栈的基本操作,编写求栈中元素个数的算法。 【题目分析】将栈值元素出栈,出栈时计数,直至栈空。 【算法】intStackLength(StackS) {//求栈中元素个数 intn=0; while(! StackEmpty(S) {n++;Pop(S); } returnn; } 算法讨论: 若要求统计完元素个数后,不能破坏原来栈,则在计数时,将原栈导入另一临时栈,计数完毕,再将临时栈倒入原栈中。 intStackLength(StackS) {//求栈中元素个数 intn=0; StackT; StackInit(T);//初始化临时栈T while(! StackEmpty(S) {n++;Push(T,Pop(S)); } while(! StackEmpty(T) {Push(S,Pop(T)); } returnn; } 3.14双向栈S是在一个数组空间V[m]内实现的两个栈,栈底分别处于数组空间的两端。 试为此双向栈设计栈初始化Init(S)、入栈Push(S,i,x)、出栈Pop(S,i)算法,其中i为0或1,用以指示栈号。 [题目分析]两栈共享向量空间,将两栈栈底设在向量两端,初始时,s1栈顶指针为-1,s2栈顶为m。 两栈顶指针相邻时为栈满。 两栈顶相向、迎面增长,栈顶指针指向栈顶元素。 #defineElemTypeint∥假设元素类型为整型 typedefstruct {ElemTypeV[m];∥栈空间 inttop[2];∥top为两个栈顶指针 }stk; stkS;∥S是如上定义的结构类型变量,为全局变量 (1) 栈初始化 intInit() {S.top[0]=-1; S.top[1]=m; return1;//初始化成功 } (2) 入栈操作: intpush(stkS,inti,intx) ∥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) {case0: S.V[++S.top[0]]=x;return (1);break; case1: S.V[--S.top[1]]=x;return (1); } }∥push (3) 退栈操作 ElemTypepop(stkS,inti) ∥退栈。 i代表栈号,i=0时为左栈,i=1时为右栈。 退栈成功返回退栈元素 ∥否则返回-1 {if(i<0||i>1){printf(“栈号输入错误\n”);exit(0);} switch(i) {case0: if(S.top[0]==-1){printf(“栈空\n”);return(-1);} elsereturn(S.V[S.top[0]--]); case1: if(S.top[1]==m{printf(“栈空\n”);return(-1);} elsereturn(S.V[S.top[1]++]); }∥switch}∥算法结束 (4) 判断栈空 intEmpty(); {return(S.top[0]==-1&&S.top[1]==m); } [算法讨论]请注意算法中两栈入栈和退栈时的栈顶指针的计算。 s1(左栈)是通常意义下的栈,而s2(右栈)入栈操作时,其栈顶指针左移(减1),退栈时,栈顶指针右移(加1)。 3.15设以数组Q[m]存放循环队列中的元素,同时设置一个标志tag,以tag=0和tag=1来区别在队头指针(front)和队尾指针(rear)相等时,队列状态为“空”还是“不空”。 试编写相应的入队(QueueIn)和出队(QueueOut)算法。 (1) 初始化 SeQueueQueueInit(SeQueueQ) {//初始化队列 Q.front=Q.rear=0;Q.tag=0; returnQ; } (2)入队 SeQueueQueueIn(SeQueueQ,inte) {//入队列 if((Q.tag==1)&&(Q.rear==Q.front))printf("队列已满\n"); else{Q.rear=(Q.rear+1)%m; Q.data[Q.rear]=e; if(Q.tag==0)Q.tag=1;//队列已不空 } returnQ; } (3)出队 ElemTypeQueueOut(SeQueueQ) {//出队列 if(Q.tag==0)printf("队列为空\n"); else {Q.front=(Q.front+1)%m; e=Q.data[Q.front]; if(Q.front==Q.rear)Q.tag=0;//空队列 } return(e); } 3.16假设用变量rear和length分别指示循环队列中队尾元素的位置和内含元素的个数。 试给出此循环队列的定义,并写出相应的入队(QueueIn)和出队(QueueOut)算法。 【算法设计】 (1)循环队列的定义 typedefstruct {ElemTypeQ[m];∥循环队列占m个存储单元 intrear,length;∥rear指向队尾元素,length为元素个数 }SeQueue; (2)初始化 SeQueueQueueInit(SeQueuecq) ∥cq为循环队列,本算法进行队列初始化 {cq.rear=0;cq.length=0;returncq; } (3)入队 SeQueueQueueIn(SeQueuecq,ElemTypex) ∥cq是以如上定义的循环队列,本算法将元素x入队 {if(cq.length==m)return(0);∥队满 else{cq.rear=(cq.rear+1)%m;∥计算插入元素位置 cq.Q[cq.rear]=x;∥将元素x入队列 cq.length++;∥修改队列长度 } return(cq); } (4) 出队 ElemTypeQueueOut(SeQueuecq) ∥cq是以如上定义的循环队列,本算法是出队算法,且返回出队元素 {if(cq.length==0)return(0);∥队空 else{intfront=(cq.rear-cq.length+1)%m;∥出队元素位置 cq.length--;∥修改队列长度 return(cq.Q[front]);∥返回对头元素 } } 3.17已知Ackerman函数定义如下: Akm(m,n)= 试写出递归和非递归算法。 (1) 递归算法 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)); } (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]); } 3.18假设称正读和反读都相同的字符序列为“回文”,例如,“abba“和“abccba”是“回文”,“abcde”和“ababab”则不是“回文“,试写一个算法,判别读入的一个以@为结束符的字符序列是否是“回文”。 【题目分析】将字符串前一半入栈,然后,栈中元素和字符串后一半进行比较。 即将第一个出栈元素和后一半串中第一个字符比较,若相等,则再出栈一个元素与后一个字符比较,……,直至栈空,结论为字符序列是回文。 在出栈元素与串中字符比较不等时,结论字符序列不是回文。 intsympthy(charstr[],chars[]) {inti=0,j,n; while(str[]! =‘\0’)i++;//查字符个数 n=i; for(i=0;i<=n/2;i++)s[i]=str[i];//前一半字符入栈 j=i; while(i {i++;j--;} if(i==n)printf(“字符串是回文\n”); elseprintf(“字符串不是回文\n”); } } 3.19设整数序列a1,a2,…,an,给出求解最大值的递归程序。 intMaxValue(inta[],intn) ∥设整数序列存于数组a中,共有n个,本算法求解其最大值 {if(n==1)max=a[1]; elseifa[n]>MaxValue(a,n-1)max=a[n]; elsemax=MaxValue(a,n-1); return(max); 3.20已知栈的三个运算定义如下: PUSH(ST,x): 元素x入ST栈;POP(ST,x): ST栈顶元素出栈并赋给变量x;Sempty(ST): 判ST栈是否为空。 利用栈的上述运算来实现队列的三个运算: QueueIn: 插入一个元素入队列;QueueOut: 删除一个元素出队列;QueueEmpty: 判队列为空。 【题目分析】栈的特点是后进先出,队列的特点是先进先出。 所以,需要用两个栈s1和s2模拟一个队列的操作: s1作输入栈,逐个元素压栈,以此模拟队列元素的入队;出队时,将栈s1退栈并逐个压入栈s2中,s1中最先入栈的元素,在s2中处于栈顶,s2退栈,相当于队列的出队,实现了先进先出。 显然,只有栈s2为空且s1也为空,才算是队列空。 (1) 入队 intQueueIn(stacks1,ElemTypex) ∥s1是容量为n的栈,栈中元素类型是ElemType ∥本算法将x入栈,若入栈成功返回1,否则返回0 {if(top1==n&&! Sempty(s2))∥top1是栈s1的栈顶指针,是全局变量 {printf(“栈满”);return(0);}∥s1满s2非空,这时s1不能再入栈 if(top1==n&&Sempty(s2))∥若s2为空,先将s1退栈,元素再压栈到s2 {while(! Sempty(s1)) {POP(s1,x);PUSH(s2,x);} PUSH(s1,x);return (1);∥x入栈,实现了队列元素的入队 } (2)出队 voidQueueOut(stacks2,s1) ∥s2是输出栈,本算法将s2栈顶元素退栈,实现队列元素的出队 {if(! Sempty(s2))∥栈s2不空,则直接出队 {POP(s2,x);printf(“出队元素为”,x);} 第4章串习题参考答案 一、基础知识题 4.1简述下列每对术语的区别: 空串和空格串;串常量与串变量;主串和子串;串变量的名字和串变量的值;静态分配的顺序串与动态分配的顺序串。 【解答】不含任何字符的串称为空串,其长度为0。 仅含有空格字符的串称为空格串,其长度为串中空格字符的个数。 空格符可用来分割一般的字符,便于人们识别和阅读,但计算串长时应包括这些空格符。 空串在串处理中可作为任意串的子串。 用引号(数据结构教学中通常用单引号,而C语言中用双引号)括起来的字符序列称为串常量,串值可以变化的量称为串变量。 串中任意个连续的字符组成的子序列被称为该串的子串。 包含子串的串又被称为该子串的主串。 子串在主串中第一次出现的第一个字符的位置称子串在主串中的位置。 串变量的与其它变量一样,要用名字引用其值,串变量的名字也是标识符,串变量的值可以修改。 串的存储也有静态存储和动态存储两种。 静态存储指用一维数组,通常一个字符占用一个字节,需要静态定义串的长度,具有顺序存储结构的优缺点。 若需要在程序执行过程中,动态地改变串的长度,则可以利用标准函数malloc()和free()动态地分配或释放存储单元,提高存储资源的利用率。 在C语言中,动态分配和回收的存储单元都来自于一个被称之为“堆”的自由存储区,故该方法可称为堆分配存储。 类型定义如下所示: typedefstruct {char*str; intlength; }HString; 4.2设有串S=’good’,T=’I︼am︼a︼student’,R=’! ’,求: (1)StringConcat(T,R) (2)SubString(T,8,7) (3)StringLength(T)(4)Index(T,’a’) (5)StringInsert(T,8,S) (6)Replace(T,SubString(T,8,7),’teacher’) 【解答】 (1)StringConcat(T,R)=’I︼am︼a︼student! ’ (2)SubString(T,8,7)=’student’ (3)StringLength(T)=14 (4)Index(T,’a’)=3 (5)StringInsert(T,8,S)=’I︼am︼a︼goodstudent’ (6)Replace(T,SubString(T,8,7),’teacher’)=’I︼am︼a︼teacher’ 4.3若串S1=‘ABCDEFG’,S2=‘9898’,S3=‘###’,S4=‘012345’,执行 concat(replace(S1,substr(S1,length(S2),length(S3)),S3),substr(S4,index(S2,‘8’),length(S2))) 操作的结果是什么? 【解答】 concat(replace(S1,substr(S1,length(S2),length(S3)),S3),substr(S4,index(S2,‘8’),length(S2))) =concat(replace(S1,substr(S1,4,3),S3),substr(S4,2,4)) =concat(replace(S1,’DEF’,S3),’1234’) =concat(‘ABC###G’,’1234’) =‘ABC###G1234’ 4.4设S为一个长度为n的字符串,其中的字符各不相同,则S中的互异的非平凡子串(非空且不同于S本身)的个数是多少? 【解答】长度为n的字符串中互异的非平凡子串(非空且不同于S本身)的个数计算如下: 长度为1的子串有n个,长度为2的子串有n-1个,长度为3的子串有n-2个,……,长度为n-1的子串有2个,长度为n的子串有1个(按题意要求这个子串就是S本身,不能计算在总数内)。 故子串个数为: (2+n)*(n-1)/2 4.5KMP算法(字符串匹配算法)较Brute(朴素的字符串匹配)算法有哪些改进? 【解答】KMP算法的最大特点是主串指针不回溯,在整个匹配过程中,对主串从头到尾扫描一遍,对于处理存储在外存上的大文件是非常有效的。 虽然Brute(朴素的字符串匹配)算法的时间复杂度是O(n*m),但在一般情况下,其实际的执行时间近似于O(n+m),因此至今仍被采用。 KMP算法仅当主串与模式间存在许多“部分匹配”的情况下才显得比Brute(朴素的字符串匹配)算法快得多。 4.6求串’ababaaababaa’的next函数值。 解答: ababaaababa next[j]: 011234223456 4.7模式串t=’abcaabbcaabdab’,求模式串的next和nextval函数的值。 abcaabbcaabdab next[j]: 01112231122312 nextval[j]: 01102131021301 4.8对S=’aabcbabcaabcaaba’,T=’bca’,画出以T为模式串,S为目标串的匹配过程。 解答: ↓i=1 第一趟匹配: aabcbabcaabcaaba b ↑j=1 ↓i=2 第二趟匹配: ababcabcacbab bc ↑j=2 ↓i=3 第三趟匹配: ababcabcacbab b ↑j=1 ↓i=7 第四趟匹配: ababcabcacbab bca(匹配成功) ↑j=4 二、算法设计题 4.11试写出用单链表表示的字符串结点类型的定义,并依次实现它的计算串长度、串赋值、判断两串相等、求子串、两串连接、求子串在串中位置的6个函数。 要求每个字符串结点中只存放一个字符。 【解答】单链表结点的类型定义如下: typedefstructNode {chardata; structNode*next; }LNode,*Li
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法与数据结构C语言版课后习题答案机械工业出版社第34章 习题参考答案 算法 数据结构 语言版 课后 习题 答案 机械工业 出版社 34 参考答案