算法与数据结构C语言习题参考答案15章DOC.docx
- 文档编号:9059806
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:31
- 大小:26.78KB
算法与数据结构C语言习题参考答案15章DOC.docx
《算法与数据结构C语言习题参考答案15章DOC.docx》由会员分享,可在线阅读,更多相关《算法与数据结构C语言习题参考答案15章DOC.docx(31页珍藏版)》请在冰豆网上搜索。
算法与数据结构C语言习题参考答案15章DOC
1.绪论
1.将下列复杂度由小到大重新排序:
A.2nB.n!
C.n5D.10000E.n*log2(n)
【答】10000 2.将下列复杂度由小到大重新排序: A.n*log2(n)B.n+n2+n3C.24D.n0.5 【答】24 3.用大“O”表示法描述下列复杂度: A.5n5/2+n2/5B.6*log2(n)+9n C.3n4+n*log2(n)D.5n2+n3/2 【答】A: O(n5/2)B: O(n)C: O(n4)D: O(n2) 4.按照增长率从低到高的顺序排列以下表达式: 4n2,log3n,3n,20n,2000,log2n,n2/3。 又n! 应排在第几位? 【答】按照增长率从低到高依次为: 2000,log3n,log2n,n2/3,20n,4n2,3n。 n! 的增长率比它们中的每一个都要大,应排在最后一位。 5.计算下列程序片断的时间代价: inti=1; while(i<=n) { printf(“i=%d\n”,i); i=i+1; } 【答】循环控制变量i从1增加到n,循环体执行n次,第一句i的初始化执行次数为1,第二句执行n次,循环体中第一句printf执行n次,第二句i从1循环到n,共执行n次。 所以该程序段总的时间代价为: T(n)=1+n+2n=3n+1=O(n) 6.计算下列程序片断的时间代价: inti=1; while(i<=n) { intj=1; while(j<=n) { intk=1; while(k<=n) { printf(“i=%d,j=%d,k=%d\n”,I,j,k); k=k+1; } j=j+1; } i=i+1; } 【答】循环控制变量i从1增加到n,最外层循环体执行n次,循环控制变量j从1增加到n,中间层循环体执行n次,循环控制变量k从1增加到n,最内层循环体执行n次,所以该程序段总的时间代价为: T(n)=1+n+n{1+n+n[1+n+2n+1]+1+1}+1 =3n3+3n2+4n+2 =O(n3) 2.线性表 1.试写一个插入算法intinsertPost_seq(palist,p,x),在palist所指顺序表中,下标为p的元素之后,插入一个值为x的元素,返回插入成功与否的标志。 【答】 数据结构 采用2.1.2节中顺序表定义。 intinsertPost_seq(PseqListpalist,intp,DataTypex){ /*在palist所指顺序表中下标为p的元素之后插入元素x*/ intq; if(palist->n>=palist->MAXNUM){/*溢出*/ printf(“Overflow! \n”); return0; } if(p<0||p>palist->n-1){/*不存在下标为p的元素*/ printf(“Notexist! \n”);return0; } for(q=palist->n-1;q>=p+1;q--)/*插入位置及之后的元素均后移一个位置*/ palist->element[q+1]=palist->element[q]; palist->element[p+1]=x;/*插入元素x*/ palist->n=palist->n+1;/*元素个数加1*/ return1; } 2试写一个删除算法deleteV_seq(palist,x),在palist所指顺序表中,删除一个值为x的元素,返回删除成功与否的标志。 【答】 数据结构 采用2.1.2节中顺序表定义。 intdeleteV_seq(PseqListpalist,p,DataTypex){ /*在palist所指顺序表中删除值为x的元素*/ intp,q; for(p=0;p if(x==palist->element[p]){ for(q=p;q palist->element[q]=palist->element[q+1]; palist->n=palist->n-1;/*元素个数减1*/ return1; } return0; } 3.设有一线性表e=(e0,e1,e2,…,en-1),其逆线性表定义为e'=(en-1,…,e2,e1,e0)。 请设计一个算法,将用顺序表表示的线性表置逆,要求逆线性表仍占用原线性表的空间。 【答】 数据结构 采用2.1.2节中顺序表的定义。 思路 考虑对数组element[]进行置逆,即把第一个元素和最后一个元素换位置,把第二个元素和倒数第二个元素换位置……。 注意 这种调换的工作只需对数组的前一半元素进行,所以设置整数变量count用于存放数组长度的一半的值。 大家可以考虑一下: 为什么不能对整个数组进行如上的对元素“换位置”的工作? (提示: 这样会将本来已经置逆的线性表又置逆回来,即又变成了原来的表。 ) 顺序表的置逆算法 voidrev_seq(PSeqListpalist){ DataTypex; intcount,i; if(palist->n==0||palist->n==1)return;/*空表或只有一个元素,直接返回*/ count=palist->n/2; for(i=0;i x=palist->element[i]; palist->element[i]=palist->element[palist->n-1-i]; palist->element[palist->n-1-i]=x; } } 代价分析 该算法中包含一个for循环,其循环次数为n/2。 因此,算法的时间代价为O(n)。 4.已知长度为n的线性表A采用顺序存储结构,请写一算法,找出该线性表中值最小的数据元素。 【答】 数据结构 采用2.1.2节中顺序表定义。 思路 设置变量min,遍历整个表,不断更新当前已经经历过的元素的最小值即可。 为方便起见,事先假设表不为空。 算法 DataTypemin_seq(PSeqListpalist){/*求非空顺序表中的最小数据元素*/ DataTypemin; inti; min=palist->element[0];/*初始化min*/ for(i=1;i if(min>palist->element[i]) min=palist->element[i]; returnmin; } 代价分析 该算法访问顺序表中每个元素各一次,时间代价为O(n)。 讨论 读者可以试图对上面的算法进行修改,使返回的值不是最小元素的值而是它的下标。 5.已知线性表A的长度为n,并且采用顺序存储结构。 写一算法,删除线性表中所有值为x的元素。 【答】 数据结构 采用2.1.2节中顺序表的定义。 思路 为了减少移动次数,可以采用快速检索的思想,用两个变量i,j记录顺序表中被处理的两端元素的下标,开始时i=0,j=n-1,边检索第i个元素边增加i,直到找到一个元素值等于x,再边检索第j个元素边减少j,直到找到一个元素值不等于x,把下标为j的元素移到下标为i的位置后重复上述过程,直到i≥j。 另用一变量count记录删除了多少个元素。 算法 voiddelx_seq(PSeqListp,DataTypex){ /*删除顺序表中所有值为x的元素,新顺序表可能不保持原有顺序*/ inti=0,j=p->n-1,count=0;/*i定位于顺序表开始处,j定位于顺序表最后*/ while(i if(p->element[i]==x){/*找到了一个要删除的元素*/ while((p->element[j]==x)&&(i! =j)){ /*从后往前找不会被删除的元素,当i,j相等时退出循环,count记录从后往前找的过程中遇到了多少个要删的元素*/ j--; count++; } if(i==j){ p->n=p->n-count-1; return; } else{ p->element[i]=p->element[j]; count++; j--; } } i++; } p->n=p->n-count; if(p->element[i]==x)p->n--; } 代价分析 该算法访问顺序表中每个元素各一次,时间代价为O(n)。 讨论 这个算法使用了一点技巧使得在中间删除元素时,避免了最后一串元素的移动。 但是,它破坏了原来线性表中元素之间的顺序关系。 如果需要保持原来的顺序应该怎样做? 这里提供一种可行的思路: 从前向后遍历表,如果元素不是x,则继续向后;如果元素是x,则寻找其后第一个不是x的元素,将这两个元素互换。 具体算法请读者自己实现。 6.写一算法,在带头结点的单链表llist中,p所指结点前面插入值为x的新结点,并返回插入成功与否的标志。 【答】 数据结构 采用2.1.3节中单链表定义。 思想: 由于在单链表中,只有指向后继结点的指针,所以只有首先找到p所指结点的前驱结点,然后才能完成插入。 而找p所指结点的前驱结点,只能从单链表的第一个结点开始,使用与locate_link类似的方式进行搜索。 算法: intinsertPre_link(LinkListllist,PNodep,DataTypex){ /*在llist带头结点的单链表中,p所指结点前面插入值为x的新结点*/ PNodep1; if(llist==NULL)return0; p1=llist; while(p1! =NULL&&p1->link! =p)p1=p1->link;/*寻找p所指结点的前驱结点*/ if(p1=NULL)return0; PNodeq=(PNode)malloc(sizeof(structNode));/*申请新结点*/ if(q=NULL){printf(“Outofspace! ! ! \n”);return0;} q->info=x; q->link=p1->link; p1->link=q; return1; } 7.写一算法,在带头结点的单链表llist中,删除p所指的结点,并返回删除成功与否的标志。 【答】 数据结构 采用2.1.3节中单链表定义。 思想: 由于在单链表中,只有指向后继结点的指针,所以只有首先找到p所指结点的前驱结点,然后才能完成删除。 而找p所指结点的前驱结点,只能从单链表的第一个结点开始,使用与locate_link类似的方式进行搜索。 intdeleteP_link(LinkListllist,PNodep){ /*在llist带头结点的单链表中,删除p所指的结点*/ PNodep1; if(llist==NULL)returnNull; p1=llist; while(p1! =NULL&&p1->link! =p)p1=p1->link;/*寻找p所指结点的前驱结点*/ if(p1=NULL)return0; p1->link=p->link; free(p);/*删除结点p*/ return1; } 8.已知list是指向无头结点的单链表的指针变量,写出删除该链表下标为i的(第i+1个)结点的算法。 【答】 数据结构 采用2.1.3节中单链表定义。 思路 依次遍历表中的每一个结点并计数,到第i+1个结点时实行删除。 由于链表是无头结点的,所以在删除第一个结点时要特别注意。 算法 intdeleteindex_link_nohead(LinkList*pllist,inti){ /*删除单链表中下标为i的结点。 删除成功返回TRUE,否则返回FALSE。 */ intj; PNodep,q; if((*pllist)==NULL||i<0)returnFALSE; if(i==0){/*如果需要删除第一个结点*/ q=(*pllist); (*pllist)=(*pllist)->link; free(q); returnTRUE; } p=(*pllist); j=0; while(p->link! =NULL&&j p=p->link; j++; } if(p->link==NULL)returnFALSE;/*此元素不存在*/ q=p->link; p->link=q->link; free(q); returnTRUE; } 代价分析 该算法访问单链表中前面i个结点,时间代价为O(i),最大不超过O(n)。 讨论 如果函数参数不是LinkList*类型而是LinkList类型,在删除i=0的结点时,程序不能正确实现,其原因请读者思考(考虑C语言的参数传递方式)。 如果单链表带表头结点,重写本题的算法。 比较这两个算法,是否能体会到表头结点的作用。 9.已知list是指向无头结点的单链表的指针变量,写出删除该链表中从下标为i的(第i+1个)结点开始的连续k个结点的算法。 【答】 数据结构 采用2.1.3节单链表定义。 思路 这道题与上题相似,只需要增加计数即可。 要注意的是应该判断给出的i和k是否合理,是不是会超出链表长度。 算法 intdel_link_nohead(LinkList*pllist,inti,intk){ /*删除单链表中从下标i开始的k个结点。 删除成功返回TRUE,否则返回FALSE。 */ intj; PNodep,q; if((*pllist)==NULL||i<0||k<=0)returnFALSE; if(i==0){/*如果需要删除从第一个结点开始的k个结点*/ for(j=0;j =NULL;j++){ q=(*pllist); (*pllist)=(*pllist)->link; free(q); } returnTRUE; } p=(*pllist); j=0; while(p->link! =NULL&&j p=p->link; j++; } if(p->link==NULL)returnFALSE;/*第i个结点不存在*/ for(j=0;j =NULL;j++){ q=p->link; p->link=q->link; free(q); } returnTRUE; } 代价分析 该算法访问单链表中前面i+k个结点,时间代价为O(i+k),最大不超过O(n)。 13.请设计一个算法,求出循环表中结点的个数。 【答】 数据结构 采用不带头结点的循环链表。 structNode; typedefstructNode*PNode; structNode{ DataTypeinfo; PNodelink; }; typedefstructNode*LinkList; 思路 遍历整个循环链表,同时计数即可。 错误算法 intcount(LinkListclist){ intcount; PNodep,q; p=clist; q=p->link; if(clist==NULL)return0;/*如果是空表*/ count=1; while(q! =p){ q=q->link; count++; } returncount; } 错误: 如果clist是一个空表,那么第5行的语句“q=p->link;”是非法的。 分析: 应把第6行语句(用下划线表示)提前1行或2行。 一定要放在语句“q=p->link;”之前。 缺点: 增加局部变量p。 分析: 这样做没有必要,因为p的初值置为clist,在程序中并没有对p做其他修改,所以程序中不需要引入p而直接使用clist即可。 算法 intcount(LinkListclist){ intcount; PNodeq; if(clist==NULL)return0;/*如果是空表*/ q=clist->link; count=1; while(q! =clist){ q=q->link; count++; } returncount; } 代价分析 该算法访问循环链表中每个结点各一次,时间代价为O(n)。 4.栈与队列 1.写一个递归算法来把整数字符串转换为整数。 (例: “43567”→43567。 ) 【答】 思路 先递归调用本算法转换除去末位外剩余的字符串,结果乘以10。 再转换末位。 将两结果相加即为所求。 算法 intstringToInt1(char*s,intstart,intend){ /*把整数字符串s中从start到end的部分转换为整数*/ if(start>end)return-1;/*转换失败*/ if(start==end)returns[end]-'0';/*只有一个字符,直接转换*/ returnstringToInt1(s,start,end-1)*10+s[end]-'0';/*先转换其他位,再转换末位*/ } intstringToInt(char*s){/*把整数字符串s转换为整数*/ inti=0; while(s[i]! ='\0')i++;/*计算字符串的长度*/ returnstringToInt1(s,0,i-1); } 代价分析 设n为字符串的长度。 该算法访问每个字符各一次,时间代价为O(n),计算字符串的长度的时间代价也为O(n)。 故总的时间代价为O(n)。 递归算法需要栈的支持,栈的大小与递归调用的深度成正比。 所以实际空间开销为O(n)。 2.编写一个算法,对于输入的十进制非负整数,将它的二进制表示打印出来。 【答】 数据结构 采用4.1.2节中栈的顺序表示。 思路 将输入的十进制数字反复除以2,直到它变为0。 将每次的数字模2的余数入栈。 栈中存放的就是所要求的二进制表示。 再将栈中的元素依次弹出打印即可。 算法 voidprint_bin(intdec_number){/*将十进制非负整数转化为二进制数打印出来*/ PSeqStackpastack; inttemp=dec_number; if(temp<0){ printf("Error! \n"); return; } pastack=createEmptyStack_seq();/*建立一个空栈*/ if(pastack==NULL)return; while(temp>0){ push_seq(pastack,temp%2); temp/=2; } while(! isEmptyStack_seq(pastack)){ printf("%d",top_seq(pastack)); pop_seq(pastack); } free(pastack); } 代价分析 设输入的十进制数字为n,则算法的时间代价为O( )。 空间代价主要是栈的大小,为O( )。 3.写一个算法: PSeqStackcreateEmptyStack_seq(intm)创建一个空栈。 数据结构 采用4.1.2节中栈的顺序表示。 PSegStackcreateEmptyStack_seq(intm){ /*创建一个空栈*/ PSeqStackpastack=(PSeqStack)malloc(sizeof(structSeqStack)); if(pastack! =NULL){ pastack->s=(DataType*)malloc(sizeof(DataType)*m); if(pastack->s){ pastack->MAXNUM=m; pastack->t=-1;/*栈顶变量赋值为-1*/ return(pastack); } elsefreepastack; } printf(“Outofspace! ! \n”);/*存储分配失败*/ returnNULL; } 4,写一个算法: intisEmptyStack_seq(PSeqStackpastack)判断pastack所指的栈是否为空栈。 数据结构 采用4.1.2节中栈的顺序表示。 intisEmptyStack_seq(PSeqStackpastack){ /*判断pastack所指的栈是否为空栈*/ if(pastack->t==-1)return1; elsereturn0; } 8.假设以循环链表表示队列,并且只设一个指针指向队尾元素结点(注意不设队头指针),试编写相应的创建空队列、入队列和出队列的算法。 【答】 数据结构 采用不带头结点的循环链表表示队列。 structNode; typedefstructNode*PNode; structNode{ DataTypeinfo; PNodelink; }; structClinkQueue{/*循环链表表示的队列类型*/ PNoder;/*尾指针*/ } typedefstructClinkQueue*PClinkQueue;/*指向循环链表表示的队列的指针类型*/ 思路 与队列的单链表表示相似,但节省了指向队头的指针变量,所以在需要找表头结点时必须通过表尾指针进行。 算法 PClinkQueuecreateEmptyQueue_clink(){/*创建空队列*/ PClinkQueuepcqu=(PClinkQueue)malloc(sizeof(structClinkQueue)); pcqu->r=NULL; returnpcqu; } voidenQueue_clink(PClinkQueuepcqu,DataTypex){/*进队列*/ PNodep; p=(PNode)malloc(sizeof(structNode)); p->info=x; if(pcqu->r==NULL){ pcqu->r=p; p->link=p; return; }/*进空队列,即往空队列中加入第一个结点*/ p->link=pcqu->r->link; pcqu->r->link=p; pcqu->r=p; } voiddeQueue_clink(PClinkQueuepcqu){/*出队列*/ PNodep; if(pcqu->r==NULL){/*是空队列*/ printf("Underflow! \n"); return; } if(pcqu->r->link==pcqu->r){/*只有一个元素的队列*/ free(pcqu->r); pcqu->r=NULL; return; } p=pcqu->r->link;/*指向队头
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 数据结构 语言 习题 参考答案 15 DOC
![提示](https://static.bdocx.com/images/bang_tan.gif)