数据结构(C语言版本)严蔚敏答案.docx
严蔚敏数据结构(C语言版)习题集答案 说明:1 .本文是对严蔚敏数据结构(C语言版)习题集一书中所有算法设计题目的解决方案,主要 作者为一具.以下网友:biwier,szm99,siice,龙抬头,iamkent,zames,birdthinking,lovebuaa 等为答 案的修订和完善工作提出了宝贵意见,在此表示感谢;2 .本解答中的所有算法均采用类c语言描述,设计原则为面向交流、面向阅读,作者不保证程 序能够上机正常运行(这种保证实际上也没有任何意义);3 .本解答原则上只给出源代码以及必要的注释,对于一些难度较高或思路特殊的题目将给出 简要的分析说明,对于作者无法解决的题目将给出必要的讨论.目前尚未解决的题目有:5.20,10.40;4 .请读者在自己已经解决了某个题目或进行了充分的思考之后,再参考本解答,以保证复习 效果;5 .由于作者水平所限,本解答中一定存在不少这样或者那样的错误和不足,希望读者们在阅 读中多动脑、勤思考,争取发现和纠正这些错误,写出更好的算法来.请将你发现的错误或其它 值得改进之处向作者报告:emailyi-ju/email第一章绪论1.16void print_descending(int x,int y,int z)按从大到小顺序输出三个数 (scanf("%d,%d,%d,&x,&y,&z);if(xvy) xv->y;>为表示交换的双目运算符,以下同if(y<z) y<->z;if(x<y) xv->y; 冒泡排序printf(M%d %d %d”,x,y,z);/print_descending1.17Status fib(int k,int m,int &f)求k阶斐波那契序列的第m项的值f (int tempd;if(k<2llm<0) return ERROR;if(m<k-l) f=0;else if (m=k-l II m=k) f=l;else(for(i=0;i<=k-2;i+) tempi=0;tempk-l= l;tempk= 1; 初始化sum=l;j=0;for(i=k+l;iv=m;i+,j+) 求出序列第k至第m个元素的值tempi=2*sum-temp|j;return OK;/fib分析:k阶斐波那契序列的第m项的值fm=fm-l+fm-24-+fm-k +fm-2+所以上述算法的时间复杂度仅为O(m).如果采用递归设计,将达到O(k八m).即使采用暂存中 间结果的方法,也将达到O(m八2).1.18typedef struct char *sport;enum male,female gender;char schoolname; 校名为 A,'B?C?D'或Echar *result;int score; resulttype;typedef struct int malescore;int femalescore;int totalscore; scoretype;void summary(resulttype resul")求各校的男女总分和团体总分,假设结果已经储存在result 数组中(scoretype scoreMAXSIZEJ;i=0;while(resulti.sport!=NULL)(switch(resulti.schoolname)(case 'A:score 0 .totalscore+=resulti.score;if(resulti.gender=O) score 0 J.malescore+=resulti.score;else score 0 .femalescore+=resulti.score;break;case 'B':score 0 .totalscore+=resulti.score;if(resulti.gender=O) score 0 .malescore+=resuIti.score;else score 0 .femalescore+=resulti.score;break;i+;for(i=0;i<5;i+)(printfC'School %d:nn,i);printf( "Total score of male: %dn", score i . malescore);printf(nTotai score of female:%dn'scorei.femalescore);printf("Total score of aH:%dnn”,scorei.totalscore);/summary1.19Status algol 19(int aARRSIZE)求 i!*2Ai 序列的值且不超过 maxint (last= 1;for(i=l ;i<=ARRSIZE;i+)(ai-l=last*2*i;if(ai-l/last)!=(2*i) reurn OVERFLOW;last=ai-l;return OK;)/algoll9分析:当某一项的结果超过了 maxint时,它除以前面一项的商会发生异常.1.20void polyvalue()(float temp;float *p=a;printf(MInput number of terms:'*);scanf(M%dn,&n);printf(MInput value of x:");scanf(H%r,&x);printf(MInput the %d coefficients from aO to a%d:n",n+l,n);p=a;xp=l ;sum=0; /xp用于存放x的i次方for(i=0;i<=n;i+)(scanf(n%f,&temp);sum+=xp*(temp);xp*=x;printf(MValue is:%f',sum);/polyvalue第二章线性表2.10Status DeleteK(SqList &ajnt ijnt k)删除线性及a中第i个元素起的k个元素 (if(i<lllk<Olli+k-l>a.length) return INFEASIBLE;for(count= 1 ;i+count-1 v=a.length-k;count+) 注意循环结束的条件a.elemi+count-1 =a.elemi+count+k-1 ;a.length-=k;return OK;/DeleteK2.11Status Insert_SqList(SqList &va,int x)把 x 插入递增有序表 va 中 (if(va.lengths 1 >va.listsize) return ERROR;va.length+;for(i=va.length-1 ;va.elemi>x&&i>=0;i)va.elemi+ l=va.elemi;va.elemi+l=x;return OK;/Insert_SqList2.12int ListComp(SqList A,SqList B)比较字符表A和B,并用返回值表示结果,值为1,表示A>B; 值为-1,表示A<B;值为0,表示A=B(for(i=l;i<=A.length&&i<=B.length;i+)if(A.elemi !=B.elemi)return A.elemi>B.elemiJ?l:-l;if(A.length=B.length) return 0;return A.length>B.length? 11;当两个字符表可以互相比较的部分完全相同时,哪个较长,哪个就较大/ListComp2.13LNode* Locate(LinkList Uint x)链表上的元素查找,返回指针 (for(p=l->next;p&&p->data!=x;p=p->next);return p;/Locate2.14ini Length(LinkList L)求链表的长度 (for(k=0,p=L;p->next;p=p->next,k+);return k;/Length2.15void ListConcat(LinkList haXinkList hb,LinkList &hc)把链表 hb 接在 ha 后面形成链表 he hc=ha;p=ha;while(p->next) p=p->next;p->next=hb;/ListConcat2.16见书后答案.2.17Status Insert(LinkList &L,int i,int b)在无头结点链表L的第i个元素之前插入元素b p=L;q=(LinkList*)malloc(sizeof(LNode);q.data=b;if(i=l)(q.next=p;L=q; 插入在链表头部 else (while(i>l) p=p->next;q>next=p,next;p>next=q; 插入在第i个元素的位置 )/Insert2.18Status Delete(LinkList &L,int i)在无头结点链表L中删除第i个元素 (if(i=l) L=L>next; 删除第一个元素 else(P=L;while(i> 1) p=p->next;p>next=p->next->next; 删除第i个元素 /Delete2.19Status Delete_Between(Linklist &L,int mink,int maxk)删除元素递增排列的链表 L 中值大于 mink且小于maxk的所有元素 (P=L;while(p->next->data<=mink) p=p->next; /p 是最后一个不大于 mink 的元素if(p->next)如果还有比mink更大的元素q=p->next;while(q->data<maxk) q=q->next; /q 是第一个不小于 maxk 的元素p->next=q;/Delete_Between2.20Status Delete_Equal(Linklist &L)删除元素递增排列的链表L中所有值相同的元素 (p=L->next;q=p->next; /p,q 指向相邻两元素while(p->next)if(p->data!=q->data)p=p->next;q=p->next; 当相邻两元素不相等时,p,q都向后推一步) else(while(q->data=p->data)free(q);q=q->next;p>next=q ;p=q ;q=p->next; 当相邻元素相等时删除多余元素/else/while /Delete_Equal2.21void reverse(SqList &A)顺序表的就地逆置(for(i=l,j=A.length;i<j;i+,j)A.elemiJ<->A.elem|j;/reverse2.22void LinkList_reverse(Linklist &L)链表的就地逆置;为简化算法,假设表长大于2 (p=L->next;q=p->next;s=q->next;p->next=NULL;while(s->next)(q->next=p;p=q;q=s;s=s>next; 把L的元素逐个插入新表表头)q->next=p;s->next=q;L->next=s; /Link Li st_re verse分析:本算法的思想是,逐个地把L的当前元素q插入新的链表头部,p为新表表头.2.23void mergel(LinkList &A,LinkList &B,LinkList &C)把链表 A 和 B 合并为 C,A 和 B 的元素间 隔排列,且使用原存储空间p=A->next;q=B->next;C=A;while(p&&q)(s=p->next;p->next=q; / B 的元素插入 if(s)(t=q->next;q->next=s; /iO A 非空,将 A 的元素插入 p=s;q=t;/while/merge 12.24void reverse_merge(LinkList &A,LinkList &B,LinkList &C)把元素递增排列的链表 A 和 B 合 并为C,且C中元素递减排列,使用原空间(pa=A->next;pb=B->next;pre=NULL; /pa 和 pb 分别指向 A,B 的当前元素 while(pallpb) (if(pa->data<pb->datall!pb)(pc=pa;q=pa->next;pa->next=pre;pa=q; /W A 的元素插入新表) else (pc=pb;q=pb->next;pb->next=pre;pb=q; / B 的元素插入新表 )pre=pc;)C=A;A->next=pc; 构造新表头 /re verse_merge分析:本算法的思想是,按从小到大的顺序依次把A和B的元素插入新表的头部pc处,最后处 理A或B的剩余元素.2.25void SqList_Intersect(SqList A,SqList B,SqList &C)求元素递增排列的线性表 A 和 B 的元素 的交集并存入C中(i=l;j=l;k=O;while(A.elemi&&B.elemj)(if(A.elemi<B.elem(j) i+;if(A.elemiJ>B.elem|jJ) j+;if(A.elemi=B.elemj)C.elem+k=A.elem;当发现了一个在A,B中都存在的元素,i+;j+; 就添力口至lj C中)/while/SqList_Intersect2.26void LinkList_Intersect(LinkList A,LinkList B,LinkList &C)在链表结构上重做上题(p=A->next;q=B->next;pc=(LNode*)malloc(sizeof(LNode);C=pc;while(p&&q)(if(p->data<q->data) p=p->next;else if(p->data>q->data) q=q->next;else(s=(LNode*)malloc(sizeof(LNode);s->data=p->data;pc->next=s;pc=s;p=p->next;q=q->next;/while/LinkList_Intersect2.27void SqList_Intersect_True(SqList&A,SqList B)求元素递增排列的线性表A和B的元素的交 集并存回A中(i=l;j=l;k=O;while(A.elemiJ&&B.elem(j)(if(A.elemi<B.elem|j) i+;else if(A.elemi>B.elemj) j+;else if(A.elemi !=A.elemkJ)(A.elem+k=A.elemi; 当发现了一个在A,B中都存在的元素i+;j+; 且C中没有,就添加到C中else i+;j+;/whilewhile(A.elemk) A.elemk+=0;/SqList_Intersect_True2.28void LinkList_Intersect_True(LinkList &A,LinkList B)在链表结构上重做上题 p=A->next;q=B->next;pc=A; while(p&&q) ( if(p->data<q->data) p=p->next; else if(p->data>q->data) q=q->next; else if(p->data!=pc->data) ( pc=pc->next;pc->data=p->data; p=p->next;q=q->next; /while /LinkList_Intersect_True 2.29 void SqList_Intersect_Delete(SqList &A,SqList B,SqList C) (i=0;j=0;k=0;m=0;/i指示A中元素原来的位置,m为移动后的位置while(i<A.length&&j<B.length&& k<C.length) ( if(B.elemj<C.elemk) j+; else if(B.elemj>C.elemk) k+; else (same=B.elem|j;找到 了相同元素 samewhile(B.elem|jJ=same) j+; while(C.elemk=same) k+;/j,k 后移到新的元素while(i<A.length&&A.elemi<same)A.elemm+=A.elemi+;需保留的元素移动到新位置while(i<A.length&&A.elemi=same) i+; 跳过相同的元素 ) /while while(i<A.length) A.elemm+=A.elemi+; /A 的剩余元素重新存储。 A.length=m; / SqList_Intersect_Delete 分析:先从B和C中找出共有元素,记为same,再在A中从当前位置开始,凡小于same的 元素均保留(存到新的位置),等于same的就跳过,到大于same时就再找下一个same. 2.30 void LinkList_Intersect_Delete(LinkList&A,LinkList BXinkList C)在链表结构上重做上题 p=B->next;q=C->next;r=A-next;while(p&&q&&r)if(p->data<q->data) p=p->next;else if(p->data>q->data) q=q->next;else(u=p->data; 确定待删除元素uwhile(r->next->data<u) r=r>next; 确定最后一个小于u的元素指针r if(r->next->data=u)(s=r->next;while(s->data=u)l=s;s=s>next;free;确定第一个大于u的元素指针s/whiler->next=s; 删除r和s之间的元素/ifwhile(p->data=u) p=p->next;while(q->data=u) q=q->next;/else/while/LinkList_Intersect_Delete2.31Status Delete_Pre(CiLNode *s)删除单循环链表中结点s的直接前驱 (p=s;while(p->next->next!=s) p=p>next; 找到 s 的前驱的前驱 pp->next=s;return OK;/Delete_Pre2.32Status DuLNode_Pre(DuLinkList &L)完成双向循环链表结点的pre域(for(p=L;!p->next->pre;p=p->next) p->next->pre=p;return OK;/DuLNode_Pre2.33Status LinkList_Divide(LinkList &L,CiList &A,CiList &B,CiList &C)把单链表 L 的元素按类 型分为三个循环链表.CiList为带头结点的单循环链表类型.(s=L->next;A=(CiList*)malloc(sizeof(CiLNode);p=A;B=(CiList*)malloc(sizeof(CiLNode);q=B;C=(CiLisl*)malloc(sizeof(CiLNode);r=C;建立头结点while(s)if(isalphabet(s->data)(p->next=s;p=s;)else if(isdigit(s->data)(q->next=s;q=s;) elser->next=s;r=s;/whilep->next=A;q->next=B;r->next二C; 完成循环链表/LinkList_Divide2.34void Print_XorLinkedList(XorLinkedList L)从左向在输出异或链表的元素值(p=L.left;pre=NULL;while(p)(prinlf("d”,p->data);q=XorP(p->LRPtr,pre);pre=p;p=q; 任何一个结点的LRPtr域值与其左结点指针进行异或运算即得到其右结点指 针)/Print_XorLinkedList2.35Status Insert_XorLinkedList(XorLinkedList &L,int x,int i)在异或链表 L 的第 i 个元素前插入元 素x (p=L.left;pre=NULL;r=(XorNode*)malloc(sizeof(XorNode);r->data=x;if(i=l) 当插入点在最左边的情况(p->LRPtr=XorP(p.LRPtr,r);r->LRPtr=p;L.left=r;return OK;)j=l ;q=p->LRPtr; 当插入点在中间的情况while(+j<i&&q)q=XorP(p->LRPtr,pre);pre=p;p=q;/while 在p,q两结点之间插入if(!q) return INFEASIBLE; /i 不可以超过表长p->LRPtr=XorP(XorP(p->LRPtr,q),r);q->LRPtr=XorP(XorP(q->LRPtr,p),r);r->LRPtr=XorP(p,q); 修改指针return OK;/Insert_XorLinkedList2.36Status Delete_XorLinkedList(XorlinkedList &L,int i)删除异或链表 L 的第 i 个元素 (p=L.left;pre=NULL;ifQ=l) 删除最左结点的情况(q=p->LRPtr;q->LRPtr=XorP(q->LRPtr,p);L.left=q;free(p);return OK;)j=l;q=p->LRPtr;while(+j<i&&q)(q=XorP(p->LRPtr,pre);pre=p;p=q;while 找到待删结点qif(!q) return INFEASIBLE; /i 不可以超过表长if(L.right=q) /q为最右结点的情况 (p->LRPtr=XorP(p->LRPtr,q);L.right=p;free(q);return OK;)r=XorP(q->LRPtr,p);/q为中间结点的情况,此时p,r分别为其左右结点p->LRPtr=XorP(XorP(p->LRPtr,q),r);>LRPlr=XorP(XorP(r->LRPlr,q),p); 修改指针free(q);return OK;/Delete_XorLinkedList2.37void OEReform(DuLinkedList &L)按1,3,5,.4,2的顺序重排双向循环链表L中的所有结点 p=L.next;while(p->next!=L&&p->next->next!=L)p->next=p->next->next;p=p->next; 此时p指向最后一个奇数结点if(p->next=L) p->next=L->pre->pre;else p->next=l->pre;p=p->next; 此时p指向最后一个偶数结点while(p->pre->pre !=L)(p->next=p->pre->pre;p=p->next;)p->next=L; 按题目要求调整了 next链的结构,此时pre链仍为原状 for(p=L;p->next!=L;p=p->next) p->next->pre=p;L,pre=p; 调整pre链的结构,同2.32方法/OEReform分析:next链和pre链的调整只能分开进行.如同时进行调整的话,必须使用堆栈保存偶数结点 的指针,否则将会破坏链表结构,造成结点丢失.2.38DuLNode * Locate_DuList(DuLinkedList &L,int x)带 freq 域的双向循环链表上的查找 (p=L.next;while(p.data!=x&&p!=L) p=p->next;if(p=L) return NULL; 没找到 p->freq+;q=p->pre;while(q->freq<=p->freq&&p!=L) q=q>pre; 查找插入位置 if(q!=p->pre) (p->pre->next=p->next;p->next->pre=p->pre;q->next->pre=p;p->next=q->next;q>next=p;p>pre=q; 调整位置 )return p;/Locate_DuList2.39float GetValue_SqPoly(SqPoly P,int x0)求升累顺序存储的稀疏多项式的值 (PolyTerm *q;xp=l;q=P.data;sum=0;ex=0;while(q->coef)(while(ex<q->exp) xp*=xO;sum+=q->coef*xp;q+; return sum;/GetValue_SqPoly2.40void Subtract_SqPoly(SqPoly Pl,SqPoly P2,SqPoly &P3)求稀疏多项式 Pl 减 P2 的差式 P3 (PolyTerm *p,*q,*r;Create_SqPoly(P3); 建立空多项式 P3p=Pl .data;q=P2.data;r=P3.data;while(p->coef&&q->coef)if(p->exp<q->exp)(r->coef=p->coef;r->exp=p->exp;p+;r+;)else if(p->exp<q->exp)(r->coef=-q->coef;r->exp=q->exp;q+;r+;)else(if(p>coefq>coef)!=0)只有同次项相减不为零时才需要存入P3中(r->coef=p->coef-q->coef;r->exp=p->exp;r+;/ifp+;q+;/else/whilewhile(p->coef) 处理Pl或P2的剩余项r->coef=p->coef;r->exp=p->exp;p+;r+;while(q->coef)(r->coef=-q->coef;r->exp=q->exp;q+;r+;/Subtract_SqPoly2.41void QiuDao_LinkedPoly(LinkedPoly &L)对有头结点循环链表结构存储的稀疏多项式L求 导(p=L->next;if(!p->data.exp)(L->next=p->next;p=p,next; WK 过常数项)while(p!=L)p->data.coef*=p->data.exp-; 对每一项求导p=p->next;/QiuDao_LinkedPoly2.42void Divide_LinkedPoly(LinkedPoly &L,&A,&B)把循环链式存储的稀疏多项式L拆成只含 奇次项的A和只含偶次项的B(p=L->next;A=(PolyNode*)malloc(sizeof(PolyNode);B=(PolyNode*)malloc(sizeof(PolyNode);pa=A;pb=B;while(p!=L)(if(p->data.exp!=2*(p->data.exp/2)pa->next=p;pa=p;)else(pb->next=p;pb=p;)p=p->next;/whilepa->next=A ;pb->next=B;/Divide_LinkedPoly第三章栈与队列3.15typedef struct Elemtype *base2;Elemtype *top2;BDStacktype; 双向栈类型Status Init_Stack(BDStacktype &tws,int m)初始化一个大小为 m 的双向栈 tws (tws.base0=(Elemtype*)malloc(sizeof(Elemtype);tws.base 1 =tws.base04-m;tws.top0=tws.base0;tws.topl =tws.basel;return OK;/Init_StackStatus push(BDStacktype &tws,int i,Elemtype x)/x 入栈,i=0 表示低端栈,i=l 表示高端栈 (if(tws.top0>tws.top 1 ) return OVERFLOW; 注意此时的栈满条件if(i=O) *tws.top0+=x;else if(i=l) *tws.topl=x;else return ERROR;return OK;/pushStatus pop(BDStacktype &tws,int i,Elemtype &x)/x 出栈,i=0 表示低端栈,i=l 表示高端栈 (if(i=O)(if(tws.top0=tws.base0) return OVERFLOW;x=*-tws.topOJ;)else if(i=l)(if(tws.top 1 J=tws.base 1 ) return OVERFLOW;x=*+tws.topl;)else return ERROR;return OK;pop3.16void Train_arrange(char *train)这里用字符串train表示火车,H表示硬席,S'表示软席 (p=train;q=train;InitStack(s);while(*p)(if(*p=H) push(s,*p); 把H存入栈中else *(q+)=*p; 把'S'调至IJ前部P+;while( !StackEmpty(s)(pop(s,c);*(q+)=c; 把H接在后部)/Train_arrange3.17int IsReverse()判断输入的字符串中&前和后部分是否为逆串,是则返回1,否则返回0 (InitStack(s);while(e=getchar() !='&')(if(e=,)return 0;/不允许在之前出现'push(s,e);while( (e=getchar()!=,<)(if(StackEmpty(s) return 0;pop(s,c);if(e!=c) return 0;if(!StackEmpty(s) return 0;return 1;/IsRe verse3.18Status Bracket_Test(char *str)判别表达式中小括号是否匹配(count=0;for(p=str;*p;p+)(if(*p=,(,) count+;else if(*p=')') count-;if (count<0) return ERROR;)if(count) return ERROR; 注意括号不匹配的两种情况return OK;/Bracket_Test3.19Status AIIBrackets_Test(char *str)判别表达式中三种括号是否匹配(InitStack(s);for(p=str;*p;p+)if(*p=0|*p=TI|*p=T) push(s,*p);else if(*p=BI*p=TII*p=)if(StackEmpty(s) return ERROR;pop(s,c);if(*p=,),&&c !=,(,) return ERROR;if(*p=t,&&c!=,) return ERROR;if(*p=,&&c!=,) return ERROR; 必须与当前栈顶