270 likes | 542 Views
数据结构习题解答 (三). helibao@mail.ustc.edu.cn 2011.12.30. 第三次作业 3.6 3.17 3.19 3.28 第六次作业 5.5 5.6 5.7 5.22 第九次作业 6.16 6.19 6.21 6.22 6.25 6.26 6.27 6.56 第十二次作业 7.11 7.13 7.42. 第三次作业. 3.6 试证明:若借助栈由输入序列 12…n 得到的输出序列为 p1p2…pn (它是输入序列的一个排列),则在输出序列中不可能出现这样的情形:存在 i<j<k 使 pj<pk<pi 。 解答: 反证法!
E N D
数据结构习题解答(三) helibao@mail.ustc.edu.cn 2011.12.30
第三次作业 • 3.6 3.17 3.19 3.28 • 第六次作业 • 5.5 5.6 5.7 5.22 • 第九次作业 • 6.16 6.19 6.21 6.22 6.25 6.26 6.27 6.56 • 第十二次作业 • 7.11 7.13 7.42
第三次作业 • 3.6 试证明:若借助栈由输入序列12…n得到的输出序列为p1p2…pn(它是输入序列的一个排列),则在输出序列中不可能出现这样的情形:存在i<j<k使pj<pk<pi。 • 解答:反证法! • 假设存在i<j<k使pj<pk<pi,则有: (1)pi>pj且i<j,pi和pj曾共存于栈中,且pi更靠近栈顶; (2)pi>pk且i<k,pi和pk曾共存于栈中,且pi更靠近栈顶; (3)由i<j<k可得,pi、pj、pk按序依次出栈。 综上,pi出栈时pj和pk尚在栈中,并且pj早于pk出栈,于是有:pj>pk。 这与题设pj<pk矛盾,证毕! 注!i<j说明pi早于pj出栈,而pi>pj说明pi晚于pj入栈。
第三次作业 • 3.17 试写出一个算法,识别一次读入一个以@为结束符的字符序列是否为形如‘序列1&序列2’模式的字符序列。其中序列1和序列2都不含字符‘&’,且序列2是序列1的逆序列。例如‘a+b&b+a’是属于该模式的字符序列,而‘1+3&3-1’则不是。 • 解答: • int IsReverse( ) //序列1和2为逆串返回1,否则返回0{ InitStack(s); while((e=getchar())!=‘&’) { push(s,e);} while((e=getchar())!='@') { if(StackEmpty(s)) { return 0;} pop(s,c); if(e!=c) { return 0;} }if(!StackEmpty(s)) { return 0;} //如“aa+b&b+a”中序列1不是2的逆序 return 1;}
第三次作业 • 3.19 假设一个算术表达式中可以包含三种括号:圆括号‘(’和‘)’、方括 号‘[’和‘]’和花括号‘{’和‘}’,且这三种括号可按任意的次序嵌套使用(如: {[()[]]})。编写判别给定表达式所包含括号是否正确配对出现的算法 (已知表达式已存入数据元素为字符的顺序表中)。 • 解答: • Status AllBrackets_Test(char *str) //判别表达式中三种括号是否匹配{ InitStack(s);for(p=str;*p;p++){ if(*p==‘(’||*p==‘[’||*p==‘{’) push(s,*p); else if(*p==‘)’||*p==‘]’||*p==‘}’) { if(StackEmpty(s)) return ERROR; pop(s,c); if(*p==‘)’&&c!=‘(’) return ERROR; if(*p==‘]’&&c!=‘[’) return ERROR; if(*p==‘}’&&c!=‘{’) return ERROR; //必须与当前栈顶括号匹配} }//for if(!StackEmpty(s)) return ERROR; //如“([]{}”不匹配 return OK; }//AllBrackets_Test
第三次作业 • 3.28 假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素结点(注意不设头指针),试编写相应的队列初始化、入队列和出队列的算法。 • 解答: void InitCiQueue(CiQueue &Q) //初始化 { Q=(CiLNode*)malloc(sizeof(CiLNode)); Q->next=Q; }//InitCiQueue
第三次作业 • 3.28(续) • void EnCiQueue(CiQueue &Q,int x) //把元素x插入循环链表表示的队列Q,Q指向队尾元素,Q->next指向头结点,Q->next->next指向队头元素{ p=(CiLNode*)malloc(sizeof(CiLNode)); p->data=x; p->next=Q->next; //直接把p加在Q的后面Q->next=p; Q=p; //修改尾指针} • Status DeCiQueue(CiQueue &Q,int x) //从循环链表表示的队列Q头部删除元素x{ if(Q==Q->next) return INFEASIBLE; //队列已空p=Q->next->next; x=p->data; Q->next->next=p->next; free(p); return OK;}//DeCiQueue
第六次作业 • 5.5 设有上三角阵(aij)nxn,将其上三角元素逐行存于数组B[m]中(m充分大),使得B[k]=aij且k=f1(i)+f2(j)+c。试推导出f1,f2和常数c(要求f1和f2中不含常数项)。 • 解答:上三角阵中有i ≤ j. aij之前有i行(0 ~ i-1) 第i行上aij之前元素个数为j-i(i ~ j-1).
第六次作业 • 5.6 设有三对角矩阵(aij)nxn,将其三条对角线上的元素存于数组B[3][n]中,使得元素B[u][v]=aij,试推导出从(i,j)到(u,v)的下标变换公式。 • 解答:下标从(0,0)开始 u=i-j+1 v=min{i, j} 备注:B[0][0…n-2] 和 B[2][0…n-2]存储两侧对角线元素 & B[1][0…n-1] 存储主对角线元素
第六次作业 • 5.7 设有三对角矩阵(aij)nxn,将其三条对角线上的元素存于数组B[3n-2]中,使得元素B[k]=aij,求: (1)用i,j表示k的下标变换公式; (2)用k表示i,j的下标变化公式; • 解答:下标从(0,0)开始 (1)i>0时,aij前有i行(0~i-1),其中第一行两个元素,其他行三个元素,共有元素数为:2+3(i-1) 第i行中,aij前有j-i个元素(i~j-1),所以: k=2+3(i-1)+(j-i)=2i+j-1 (i=0时等式也满足) (2)j-1≤i≤j+1 =>3j-2≤k+1≤3j+2 => j-2/3≤(k+1)/3 ≤j+2/3 => j= 于是,i=
第六次作业 • 5.22 假设系数矩阵A和B均以三元组顺序表作为存储结构。试写出满足以下的矩阵相加的算法:假设三元组顺序表A的空间足够大,将矩阵B加到矩阵A上,不增加A,B之外的附加空间,你的算法能否达到O(m+n)的时间复杂度,其中m和n分别为A,B矩阵中非零元的数目。 • 解答: void TSMatrix_Addto(TSMatrix &A,TSMatrix B)//将三元组矩阵B加到A上 { for(i=0;i<A.tu;i++) { //把A的所有元素都移到尾部以腾出位置 A.data[MAXSIZE-A.tu+i]=A.data[i]; } pa=MAXSIZE-A.tu ;pb=0;pc=0; for(pb=0; pb<B.tu; pb++) { if (A.data[pa].i==B.data[pb].i){
第六次作业 • 5.22(续) if(A.data[pa].j==B.data[pb].j) { ne = A.data[pa].v + B.data[pb].v; if(ne) { A.data[pc].i = A.data[pa].i; A.data[pc].j = A.data[pa].j; A.data[pc].v = ne; pc++; } // end if(ne!=0) pa++; pb++; } //end if(…) else if(A.data[pa].j<B.data[pb].j){ A.data[pc].i = A.data[pa].i; A.data[pc].j = A.data[pa].j; A.data[pc].v = A.data[pa].v; pc++; pa++; } else {//A.data[pa].j>B.data[pb].j A.data[pc].i = B.data[pb].i; A.data[pc].j = B.data[pb].j; A.data[pc].v = B.data[pb].v; pc++; pb++; } } //end if(…)
第六次作业 • 5.22(续2) else if (A.data[pa].i<B.data[pb].i) { A.data[pc].i = A.data[pa].i; A.data[pc].j = A.data[pa].j; A.data[pc].v = A.data[pa].v; pc++; pa++; } else {//A.data[pa].i>B.data[pb].i A.data[pc].i = B.data[pb].i; A.data[pc].j = B.data[pb].j; A.data[pc].v = B.data[pb].v; pc++; pb++; } } //end for(…) for(i=A.tu;i<MAXSIZE;i++) { //清除原来的A中记录 A.data[i]={0,0,0}; } A.tu=pc; } //end TSMatrix_Addto()
第九次作业 • 6.16 将下列二叉链表改为先序线索链表(不画出树的形态)。 • 解答:
第九次作业 • 6.19 分别画出和下列树对应的二叉树。 • 解答:
第九次作业 • 6.21 画出和下列二叉树对应的森林。 • 解答:
第九次作业 • 6.22 对于6.19题中给出的各树分别求出以下遍历序列:(1)先根序列;(2)后根序列。 • 解答:遍历原树,而不是对应的二叉树! • (1) • (a) A (b) ABC (c) ABC • (d) ABCEIJFGKHD • (2) • (a) A (b) CBA (c) BCA • (d) BIJEFKGHCDA
第九次作业 • 6.23 画出和下列已知序列对应的树T: 树的先根次序访问序列为GFKDAIEBCHJ 树的后根次序访问序列为DIAEKFCJHBG。 • 解答:
第九次作业 • 6.26 假设用于通信的电文仅由8个字母组成,字母在电文中出现的频率分别为0.07,0.19,0.02,0.06, 0.32,0.03,0.21,0.10。试为这8个字母设计Huffman编码。使用0~7的二进制表示的形式是另一种编码方案。对于上述两种实例,比较两种方案的优缺点。 • 解答: 平均码长比为 2.61:3 Huffman编码较优
第九次作业 • 6.27 假设一颗二叉树的先序序列为EBADCFHGI KJ和中序序列为ABCDEFGHIJK。请画出该树。 解答:
第九次作业 • 6.56 试写出一个算法,在先序后继线索二叉树中,查找给定结点*p在先序序列中的后继(假设二叉树的根结点未知)。并讨论实现此算法对存储结构有何要求? • 解答: BTNode *PreOrder_Next(BTNode *p) //在先序后继线索二叉树中 //查找结点p的先序后继,并返回指针 {if(p->lchild) return p->lchild;//有左孩子,则左孩子即为后继 else return p->rchild; //无左孩子但有右孩子,则右孩子为 //后继,否则rchild指向的右线索即为后继 }//PreOrder_Next • 存储结构要求:只需要添加Rtag域,为1则rchild指向后继,否则指向右孩子。
第十二次作业 • 7.11 试利用Dijkstra算法求解题7.11图中从顶点a到其他各顶点间的最短路径,写出执行算法过程中各步的状态。 • 解答:
第十二次作业 • 7.13 试利用Floyd算法求解7.13图所示有向图中各对顶点之间的最短路径。 • 解答:根据PPT上算法迭代运算即可 初始值A(-1),P(-1) 四个顶点四次迭代,依次得到 A0,P0; A1,P1; A2,P2; A3,P3 详细过程略。。。
第十二次作业 • 7.42 以邻接表作存储结构实现求从源点到其余各顶点的最短路径的Dijkstra算法 • 解答:在PPT上算法的基础上修改! typedef int Distance[n]; typedef int Path[n] void Dijkstra ( ALGraph G, Distance D, Path P, int s ){ //0≤s ≤n-1,若<i,j>不是边,则G…… Boolean S[n];//S是红点集。S[i]为真表示i为红点,否则为白点 for ( i=0; i<n; i++) { //初始化 S[i]=FALSE; D[i]=INFINITY; for (p=G.vertices[s].firstarc; !p; p=p->nextarc) { D[p->adjvex] = *(p->info); //s为始点的边长,作为初始的估计距离 } if ( D[i]<Infinity ) P[i]=s; //<s,i>∊E, s是i的前驱(双亲) else P[i]=-1; // i无前驱,注意P[s]亦无前驱 } S[s]=TRUE; D[s]=0;//红点集仅有源点s
第十二次作业 • 7.42(续) for ( i=0; i<n-1; i++) { //向红点集S扩充n-1个红点 min=Infinity; for ( j=0; j<n; j++ ) //选估计距离最小的白点k(离s最近){ if ( !S[ j ] && D[ j ]<min ) { min=D[ j ]; k=j; } } if (min==Infinity) return; // 白点集为空或只剩下无最短路径的点 S[k]=TRUE; // k加入红点集 for (p=G.vertices[k].firstarc; !p; p=p->nextarc){ j= p->adjvex; if ( !S[ j ] && D[j]>D[k]+*(p->info) ) {//调整剩余白点的估计距离 D[j] = D[k]+*(p->info) ;//修改白点j的估计距离,使之离s更近 P[j] = k; // k是j的前驱 } }//endfor }
祝大家考试顺利 谢谢!