收藏 分享(赏)

《数据结构题集》答案 第7章 图.doc

上传人:weiwoduzun 文档编号:5640482 上传时间:2019-03-10 格式:DOC 页数:46 大小:119.50KB
下载 相关 举报
《数据结构题集》答案 第7章 图.doc_第1页
第1页 / 共46页
《数据结构题集》答案 第7章 图.doc_第2页
第2页 / 共46页
《数据结构题集》答案 第7章 图.doc_第3页
第3页 / 共46页
《数据结构题集》答案 第7章 图.doc_第4页
第4页 / 共46页
《数据结构题集》答案 第7章 图.doc_第5页
第5页 / 共46页
点击查看更多>>
资源描述

1、第七章 图 7.14 Status Build_AdjList(ALGraph scanf(“%d“,if(vnextarc;q=q-nextarc);q-nextarc=p;p-adjvex=j;p-nextarc=NULL;/whilereturn OK;/Build_AdjList 7.15 /本题中的图 G 均为有向无权图,其余情况容易由此写出Status Insert_Vex(MGraph G.vexs+G.vexnum=v;return OK;/Insert_Vex Status Insert_Arc(MGraph /将待删除顶点交换到最后一个顶点for(i=0;iadjvex=j

2、;p-nextarc=NULL;if(!G.verticesi.firstarc) G.verticesi.firstarc=p;elsefor(q=G.verticesi.firstarc;q-q-nextarc;q=q-nextarc)if(q-adjvex=j) return ERROR; /边已经存在q-nextarc=p;G.arcnum+;return OK;/Insert_Arc 7.17 /为节省篇幅,本题只给出较为复杂的 Delete_Vex 算法 .其余算法请自行写出. Status Delete_Vex(OLGraph G.xlisti.firstin=q-hlink;f

3、ree(q);G.arcnum-;else /否则for(p=G.xlisti.firstin;pp=p-hlink);if(p)q=p-hlink;p-hlink=q-hlink;free(q);G.arcnum-;/else/forfor(i=0;iheadvex=m) /如果待删除的边是尾链上的第一个结点q=G.xlisti.firstout;G.xlisti.firstout=q-tlink;free(q);G.arcnum-;else /否则for(p=G.xlisti.firstout;pp=p-tlink);if(p)q=p-tlink;p-tlink=q-tlink;free(

4、q);G.arcnum-;/else/forfor(i=m;ihlink)p-headvex-;for(p=G.xlisti.firstout;p;p=p-tlink)p-tailvex-; /修改各链中的顶点序号G.vexnum-;return OK;/Delete_Vex 7.18 /为节省篇幅,本题只给出 Delete_Arc 算法.其余算法请自行写出. Status Delete_Arc(AMLGraph elsefor(p=G.adjmulisti.firstedge;pp=p-ilink);if (!p) return ERROR; /未找到p-ilink=p-ilink-ilin

5、k; /在 i 链表中删除该边if(G.adjmulistj.firstedge-ivex=i)G.adjmulistj.firstedge=G.adjmulistj.firstedge-jlink;elsefor(p=G.adjmulistj.firstedge;pp=p-jlink);if (!p) return ERROR; /未找到q=p-jlink;p-jlink=q-jlink;free(q); /在 i 链表中删除该边G.arcnum-;return OK;/Delete_Arc 7.19 Status Build_AdjMulist(AMLGraph scanf(“%d“,if

6、(vivex=i;p-jvex=j;p-ilink=NULL;p-jlink=NULL; /边结点赋初值if(!G.adjmulisti.firstedge) G.adjmulisti.firstedge=p;elseq=G.adjmulisti.firstedge;while(q)r=q;if(q-ivex=i) q=q-ilink;else q=q-jlink;if(r-ivex=i) r-ilink=p;/注意 i 值既可能出现在边结点的 ivex 域中,else r-jlink=p; /又可能出现在边结点的 jvex 域中/else /插入 i 链表尾部if(!G.adjmulistj

7、.firstedge) G.adjmulistj.firstedge=p;elseq=G.adjmulisti.firstedge;while(q)r=q;if(q-jvex=j) q=q-jlink;else q=q-ilnk;if(r-jvex=j) r-jlink=p;else r-ilink=p;/else /插入 j 链表尾部/forreturn OK;/Build_AdjList 7.20 int Pass_MGraph(MGraph G)/判断一个邻接矩阵存储的有向图是不是可传递的,是则返回 1,否则返回 0for(x=0;xnextarc)y=p-adjvex;for(q=G.

8、verticesy.firstarc;q;q=q-nextarc)z=q-adjvex;if(z!=x/for/for/Pass_ALGraph int is_adj(ALGraph G,int m,int n)/判断有向图 G 中是否存在边(m,n),是则返回 1,否则返回 0for(p=G.verticesm.firstarc;p;p=p-nextarc)if(p-adjvex=n) return 1;return 0;/is_adj 7.22 int visitedMAXSIZE; /指示顶点是否在当前路径上 int exist_path_DFS(ALGraph G,int i,int

9、j)/深度优先判断有向图 G 中顶点 i 到顶点j 是否有路径,是则返回 1,否则返回 0if(i=j) return 1; /i 就是 jelsevisitedi=1;for(p=G.verticesi.firstarc;p;p=p-nextarc)k=p-adjvex;if(!visitedk/i 下游的顶点到 j 有路径/for/else/exist_path_DFS 7.23 int exist_path_BFS(ALGraph G,int i,int j)/广度优先判断有向图 G 中顶点 i 到顶点j 是否有路径,是则返回 1,否则返回 0int visitedMAXSIZE;Ini

10、tQueue(Q);EnQueue(Q,i);while(!QueueEmpty(Q)DeQueue(Q,u);visitedu=1;for(p=G.verticesi.firstarc;p;p=p-nextarc)k=p-adjvex;if(k=j) return 1;if(!visitedk) EnQueue(Q,k);/for/whilereturn 0;/exist_path_BFS 7.24 void STraverse_Nonrecursive(Graph G)/非递归遍历强连通图 Gint visitedMAXSIZE;InitStack(S);Push(S,GetVex(S,1

11、); /将第一个顶点入栈visit(1);visited=1;while(!StackEmpty(S)while(Gettop(S,i)if(jvisitedj=1;Push(S,j); /向左走到尽头/whileif(!StackEmpty(S)Pop(S,j);Gettop(S,i);k=NextAdjVex(G,i,j); /向右走一步if(kvisitedk=1;Push(S,k);/if/while/Straverse_Nonrecursive分析:本算法的基本思想与二叉树的先序遍历非递归算法相同 ,请参考 6.37.由于是强连通图,所以从第一个结点出发一定能够访问到所有结点. 7.

12、25 见书后解答. 7.26 Status TopoNo(ALGraph G)/按照题目要求顺序重排有向图中的顶点int newMAXSIZE,indegreeMAXSIZE; /储存结点的新序号n=G.vexnum;FindInDegree(G,indegree);InitStack(S);for(i=1;inextarc)k=p-adjvex;if(!(-indegreek) Push(S,k);/for/whileif(count0)visitedi=1;for(p=G.verticesi.firstarc;p;p=p-nextarc)l=p-adjvex;if(!visitedl)if

13、(exist_path_len(G,l,j,k-1) return 1; /剩余路径长度减一/forvisitedi=0; /本题允许曾经被访问过的结点出现在另一条路径中/elsereturn 0; /没找到/exist_path_len 7.28 int pathMAXSIZE,visitedMAXSIZE; /暂存遍历过程中的路径 int Find_All_Path(ALGraph G,int u,int v,int k)/求有向图 G 中顶点 u 到 v 之间的所有简单路径,k 表示当前路径长度pathk=u; /加入当前路径中visitedu=1;if(u=v) /找到了一条简单路径p

14、rintf(“Found one path!n“);for(i=0;pathi;i+) printf(“%d“,pathi); /打印输出elsefor(p=G.verticesu.firstarc;p;p=p-nextarc)l=p-adjvex;if(!visitedl) Find_All_Path(G,l,v,k+1); /继续寻找visitedu=0;pathk=0; /回溯/Find_All_Path main().Find_All_Path(G,u,v,0); /在主函数中初次调用,k 值应为 0./main 7.29 int GetPathNum_Len(ALGraph G,in

15、t i,int j,int len)/求邻接表方式存储的有向图 G的顶点 i 到 j 之间长度为 len 的简单路径条数if(i=j /找到了一条路径,且长度符合要求else if(len0)sum=0; /sum 表示通过本结点的路径数visitedi=1;for(p=G.verticesi.firstarc;p;p=p-nextarc)l=p-adjvex;if(!visitedl)sum+=GetPathNum_Len(G,l,j,len-1)/剩余路径长度减一/forvisitedi=0; /本题允许曾经被访问过的结点出现在另一条路径中/elsereturn sum;/GetPathN

16、um_Len 7.30 int visitedMAXSIZE;int pathMAXSIZE; /暂存当前路径int cyclesMAXSIZEMAXSIZE; /储存发现的回路所包含的结点int thiscycleMAXSIZE; /储存当前发现的一个回路int cycount=0; /已发现的回路个数 void GetAllCycle(ALGraph G)/求有向图中所有的简单回路for(v=0;vnextarc)w=p-adjvex;if(!visitedw) DFS(G,w,k+1);else /发现了一条回路for(i=0;pathi!=w;i+); /找到回路的起点for(j=0;

17、pathi+j;i+) thiscyclej=pathi+j;/把回路复制下来if(!exist_cycle() cyclescycount+=thiscycle;/如果该回路尚未被记录过,就添加到记录中for(i=0;i=0;i-) /第二次逆向的深度优先遍历v=finished(i);if(!visitedv)printf(“n“); /不同的强连通分量在不同的行输出DFS2(G,v);/for/Get_SGraph void DFS1(OLGraph G,int v)/第一次深度优先遍历的算法visitedv=1;for(p=G.xlistv.firstout;p;p=p-tlink)w

18、=p-headvex;if(!visitedw) DFS1(G,w);/forfinished+count=v; /在第一次遍历中建立 finished 数组/DFS1 void DFS2(OLGraph G,int v)/第二次逆向的深度优先遍历的算法visitedv=1;printf(“%d“,v); /在第二次遍历中输出结点序号for(p=G.xlistv.firstin;p;p=p-hlink)w=p-tailvex;if(!visitedw) DFS2(G,w);/for/DFS2分析:求有向图的强连通分量的算法的时间复杂度和深度优先遍历相同 ,也为O(n+e). 7.32 void

19、 Forest_Prim(ALGraph G,int k,CSTree jnextarc)if(p-adjvex=k) closedgej.lowcost=p-cost;/ifclosedgek.lowcost=0;for(i=1;inextarc)if(p-costadjvex.lowcost)closedgep-adjvex=k,p-cost;/ifelse Forest_Prim(G,k); /对另外一个连通分量执行算法/for/Forest_Prim void Addto_Forest(CSTree /找到结点 i 对应的指针 p,过程略q=(CSTNode*)malloc(sizeo

20、f(CSTNode);q-data=j;if(!p) /起始顶点不属于森林中已有的任何一棵树p=(CSTNode*)malloc(sizeof(CSTNode);p-data=i;for(r=T;r-nextsib;r=r-nextsib);r-nextsib=p;p-firstchild=q; /作为新树插入到最右侧else if(!p-firstchild) /双亲还没有孩子p-firstchild=q; /作为双亲的第一个孩子else /双亲已经有了孩子for(r=p-firstchild;r-nextsib;r=r-nextsib);r-nextsib=q; /作为双亲最后一个孩子的兄

21、弟/Addto_Forest main().T=(CSTNode*)malloc(sizeof(CSTNode); /建立树根T-data=1;Forest_Prim(G,1,T);./main分析:这个算法是在 Prim 算法的基础上添加了非连通图支持和孩子兄弟链表构建模块而得到的,其时间复杂度为 O(n2). 7.33 typedef struct int vex; /结点序号int ecno; /结点所属的连通分量号 VexInfo;VexInfo vexsMAXSIZE; /记录结点所属连通分量号的数组 void Init_VexInfo(VexInfo i1)GetMinEdge(E

22、dgeSet,u,v); /选出最短边if(!is_ec(vexs,u,v) /u 和 v 属于不同连通分量Addto_CSTree(T,u,v); /加入到生成树中merge_ec(vexs,vexsu.ecno,vexsv.ecno); /合并连通分量ecnum-;DelMinEdge(EdgeSet,u,v); /从边集中删除/while/MinSpanTree_Kruscal void Addto_CSTree(CSTree /找到结点 i 对应的指针 p,过程略q=(CSTNode*)malloc(sizeof(CSTNode);q-data=j;if(!p-firstchild)

23、/双亲还没有孩子p-firstchild=q; /作为双亲的第一个孩子else /双亲已经有了孩子for(r=p-firstchild;r-nextsib;r=r-nextsib);r-nextsib=q; /作为双亲最后一个孩子的兄弟/Addto_CSTree分析:本算法使用一维结构体变量数组来表示等价类 ,每个连通分量所包含的所有结点属于一个等价类.在这个结构上实现了初始化,判断元素是否等价(两个结点是否属于同一个连通分量),合并等价类(连通分量)的操作. 7.34 Status TopoSeq(ALGraph G,int new )/按照题目要求给有向无环图的结点重新编号,并存入数组 n

24、ew 中int indegreeMAXSIZE; /本算法就是拓扑排序FindIndegree(G,indegree);Initstack(S);for(i=0;inextarc)k=p-adjvex;if(!(-indegreek) Push(S,k);/whileif(countnextarc)w=p-adjvex;if(!visitedw) DFS(G,w);/DFS 7.36 void Fill_MPL(ALGraph for(i=0;inextarc)j=p-adjvex;if(G.verticesj.MPL=0) k=Get_MPL(G,j);if(kmax) max=k; /求其

25、直接后继顶点 MPL 的最大者G.verticesi=max+1;/再加一,就是当前顶点的 MPLreturn max+1;/else/Get_MPL 7.37 int maxlen,pathMAXSIZE; /数组 path 用于存储当前路径int mlpMAXSIZE; /数组 mlp 用于存储已发现的最长路径 void Get_Longest_Path(ALGraph G)/求一个有向无环图中最长的路径maxlen=0;FindIndegree(G,indegree);for(i=0;imaxlenjnextarc)j=p-adjvex;if(!visitedj) DFS(G,j,len

26、+1);/elsepathi=0;visitedi=0;/DFS 7.38 void NiBoLan_DAG(ALGraph G)/输出有向无环图形式表示的表达式的逆波兰式FindIndegree(G,indegree);for(i=0;iadjvex);PrintNiBoLan_DAG(G,p-nexarc-adjvex);printf(“%c“,c);/PrintNiBoLan_DAG 7.39 void PrintNiBoLan_Bitree(Bitree T)/在二叉链表存储结构上重做上一题if(T-lchild) PrintNiBoLan_Bitree(T-lchild);if(T-

27、rchild) PrintNiBoLan_Bitree(T-rchild);printf(“%c“,T-data);/PrintNiBoLan_Bitree 7.40 int Evaluate_DAG(ALGraph G)/给有向无环图表示的表达式求值FindIndegree(G,indegree);for(i=0;iadjvex);v2=Evaluate_imp(G,p-nextarc-adjvex);return calculate(v1,G.verticesi.optr,v2);/Evaluate_imp分析:本题中,邻接表的 vertices 向量的元素类型修改如下:struct en

28、um tagNUM,OPTR;union int value;char optr;ArcNode * firstarc; Elemtype; 7.41 void Critical_Path(ALGraph G)/利用深度优先遍历求网的关键路径FindIndegree(G,indegree);for(i=0;inextarc)dut=*p-info;if(vei+dutvep-adjvex)vep-adjvex=vei+dut;DFS1(G,p-adjvex);/DFS1 void DFS2(ALGraph G,int i)if(!G.verticesi.firstarc) vli=vei;el

29、sefor(p=G.verticesi.firstarc;p;p=p-nextarc)DFS2(G,p-adjvex);dut=*p-info;if(vlp-adjvex-dutadjvex-dut;/else/DFS2 7.42 void ALGraph_DIJ(ALGraph G,int v0,Pathmatrix vnextarc)Dp-adjvex=*p-info; /给 D 数组赋初值for(v=0;vnextarc)w=p-adjvex;if(!finalw/遍历左子树Visit(T-data);/通过函数指针调用它所指的函数来访问结点Inorder(T-rchild,Visit)

30、;/遍历右子树其中 Visit 是一个函数指针,它指向形如 void f(DataTypex)的函数。因此我们可以将访问结点的操作写在函数 f 中通过调用语句 Inorder(root,f)将 f 的地址传递给 Visit,来执行遍历操作。请写一个打印结点数据的函数,通过调用上述算法来完成书中 6.3 节的中序遍历。6.22 解:这个函数如下:void PrintNode(BinTree T)printf(“%c“,T-data);为了验证这个函数是否正确,要先建立一棵二叉树,然后调用这个中序遍历算法-/定义二叉树链式存储结构typedef char DataType;/定义 DataType

31、 类型typedef struct nodeDataType data;struct node *lchild, *rchild;/左右孩子子树BinTNode; /结点类型typedef BinTNode *BinTree ;/二叉树类型#include #include void CreatBinTree(BinTree *T)/输入序列是先序序列 /构造二叉链表。T 是指向根的指针,故修改了*T 就修改了实参char ch;if (ch=getchar()= )*T=NULL;else /读入非空格*T=(BinTNode *)malloc(sizeof(BinTNode);/生成结点(

32、*T)-data=ch;CreatBinTree( /构造左子树CreatBinTree( /构造右子树/-void PrintNode(DataType x) /题目要求的打印函数printf(“%c“,x);/-void Inorder(BinTree T,void(* Visit)(DataType x)if(T)Inorder(T-lchild,Visit);/遍历左子树Visit(T-data); /通过函数指针调用它所指的函数访问结点Inorder(T-rchild,Visit);/遍历右子树void main() /现在开始测试啦BinTree root; /定义一个根结点Cre

33、atBinTree( /建立二叉链表printf(“n“);Inorder(root,PrintNode);/调用函数,注意传递的是函数名(它就是地址)printf(“n“);/运行时请输入“ab c“(注意 b 后和 c 后面各两个空格)再回车,可生成一个以 a 为根的两片叶子的二叉树,看看打印的结果对不对?6.23 以二叉链表为存储结构,分别写出求二叉树结点总数及叶子总数的算法。解:利用中序遍历,我们很容易地就能找到这个算法每访问一次非空结点就给变量 nodes 加上 1;每访问到一个其左右子树皆空的结点就给变量 leaves 加上 1,最后就得到结果了:完整程序如下所示:/定义二叉树链式

34、存储结构等内容,为方便起见我们将这一段内容存为 bintree.h 文件,以后只在程序中加入这个头文件就是了。/-bintree.h 文件开始-typedef char DataType;/定义 DataType 类型typedef struct nodeDataType data;struct node *lchild, *rchild;/左右孩子子树BinTNode; /结点类型typedef BinTNode *BinTree ;/二叉树类型#include #include void CreatBinTree(BinTree *T) /构造二叉链表,注意:输入序列是先序序列char c

35、h;if (ch=getchar()= )*T=NULL;else /读入非空格*T=(BinTNode *)malloc(sizeof(BinTNode);/生成结点(*T)-data=ch;CreatBinTree( /构造左子树CreatBinTree( /构造右子树/-文件结束-/-以下两个函数为题目要求算法-int Node(BinTree T) /算结点数int static nodes=0;/静态变量保留每次递归调用后的值if(T) /使用中序遍历Node(T-lchild); /遍历左子树nodes+; /结点数加 1Node(T-rchild); /遍历右子树return n

36、odes;int Leaf(BinTree T) /算叶子数int static leaves=0;/静态变量保证其值不会随递归调用而消失if(T) /使用中序遍历Leaf(T-lchild); /遍历左子树if(!(T-lchild|T-rchild)/左右孩子均为空leaves+; /叶子数加 1Leaf(T-rchild); /遍历右子树return leaves;/算法结束-#include void main() /测试程序BinTree root;CreatBinTree(int nodes=Node(root);int leaves=Leaf(root);printf(“nnod

37、es=%d leaves=%d“,nodes,leaves);6.24 以二叉链表为存储结构,分别写出求二叉树高度及宽度的算法,所谓宽度是指二叉树的各层上,具有结点数最多的那一层上的结点总数。解:要想求出二叉树的高度,可以采用前序遍历,设一个个记录高度的变量 h,在访问结点时查询该结点是否有孩子,有则高度加 1,其中根结点比特殊,自身算一层。要求二叉树的宽度的话,则可根据树的高度设置一个数组,在访问结点时计算该结点下一层的孩子数并存入相应数组元素中,遍历左子树后向上返回一层计算右子树的宽度,并取出最大的一个数组元素作为树的宽度。#include #include “bintree.h“#def

38、ine M 10 /假设二叉树最多的层数int Height(BinTree T)/求树的深度 /求深度算法由阮允准更正,在此深表感谢。int lhigh,rhigh,high=0;if(T!=NULL)lhigh=Height(T-lchild);/左子树高度rhigh=Height(T-rchild);/右子树高度high=(lhighrhigh?lhigh:rhigh)+1;/树的高度等于左子树、右子树之间的大者加上根结点 1。return high;int Width(BinTree T)int static nM;/向量存放各层结点数int static i=1;int static

39、 max=0;/最大宽度if(T)if(i=1) /若是访问根结点n+; /第 1 层加 1i+; /到第 2 层if(T-lchild)/若有左孩子则该层加 1n+;if(T-rchild)/若有右孩子则该层加 1n+;else /访问子树结点i+; /下一层结点数if(T-lchild)n+;if(T-rchild)n+;if(maxlchild);/遍历左子树i-; /往上退一层Width(T-rchild);/遍历右子树return max;/算法结束void main() /测试程序BinTree root;CreatBinTree (printf(“nHeight of BinTr

40、ee:%d“,Height(root);printf(“nWidth of BinTree:%d“,Width(root);6.25 以二叉链表为存储结构, 写一算法交换各结点的左右子树。要交换各结点的左右子树,最方便的办法是用后序遍历算法,每访问一个结点时把两棵子树的指针进行交换,最后一次访问是交换根结点的子树。#include #include “bintree.h“void ChangeBinTree(BinTree *T) /交换子树if(*T) /这里以指针为参数使得交换在实参的结点上进行/后序遍历BinTree temp;ChangeBinTree(ChangeBinTree(te

41、mp=(*T)-lchild;(*T)-lchild=(*T)-rchild;(*T)-rchild=temp;void PrintNode(BinTree T) /以前序序列打印结点数据if(T)printf(“%c“,T-data);PrintNode(T-lchild);PrintNode(T-rchild);void main() /测试程序BinTree root;CreatBinTree(/建立二叉链表PrintNode(root); /输出原表printf(“n“);ChangeBinTree(/交换子树PrintNode(root); /输出新表printf(“n“);/可输入

42、 “abc d ef g “来测试 (注意空格 ),看看对不对 ?6.26 以二叉链表为存储结构,写一个拷贝二叉树的算法 void CopyTree(BinTree root,BinTree*newroot),其中新树的结点是动态申请的,为什么 newroot 要说明为 BinTree 型指针的指针 ?题目问为什么 newroot 要说明为 BinTree 型指针,其实我们前面已经知道,因为调用函数只能进行值传递 ,当返回类型为 void 时,就必须把实参的地址传给函数,否则函数不会对实际参数进行任何操作 ,也就得不到所需结果了。程序如下:#include #include #include

43、“bintree.h“void CopyTree(BinTree root,BinTree *newroot) /拷贝二叉树if(root)/如果结点非空 /按前序序列拷贝*newroot=(BinTNode *)malloc(sizeof(BinTNode);/生成新结点(*newroot)-data=root-data;/拷贝结点数据CopyTree(root-lchild,/拷贝左子树CopyTree(root-rchild,/拷贝右子树else /如果结点为空*newroot=NULL;/将结点置空void PrintNode(BinTree T) /以前序序列打印结点数据if(T)printf(“%c“,T-data);PrintNode(T-lchild);PrintNode(T-rchild);void main( )/测试程序BinTree root;BinTree New;/构造一个动态二叉树根CreatBinTree(/构造一棵二叉树PrintNode(root);printf(“n“);CopyTree(root,/注意此处用

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 经营企划

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报