数据结构-图习题
数据结构第7章图习题

、单项选择题1.在一个无向图 G 中,所有顶点的度数之和等于所有边数之和的 _________ 倍A .l/2B .1D .42.在一个有向图中, 所有顶点的入度之和等于所有顶点的出度之和的 ________倍A .l/2 C .2D .43.一个具有 n 个顶点的无向图最多包含 _____ 条边。
A .nB .n +1C .n-1D .n(n-1)/24.一个具有 n 个顶点的无向完全图包含 _____ 条边。
A .n(n-l)B .n(n+l)C .n(n-l)/2D .n(n-l)/25.一个具有 n 个顶点的有向完全图包含 _____ 条边。
A .n(n-1)B .n(n+l)C .n(n-l)/2D .n(n+l)/2 6.对于具有 n 个顶点的图,若采用邻接矩阵表示,则该矩阵的大小为A. nB. n><h C .n-17 .无向图的邻接矩阵是一个 ______A .对称矩阵 C .上三角矩阵8.对于一个具有 n 个顶点和 e 条边的无 (有)向图,若采用邻接表表示,则表头 向量的大小为 。
A .n C . 2nD . 2e 9.对于一个具有 n 个顶点和 e 条边的无 (有)向图,若采用邻接表表示,则所有 顶C .2B .1 D . (n-I)也-I)B .零矩阵 D .对角矩阵 B .e点邻接表中的结点总数为_________ 。
B. eC. 2nD. 2e10.在有向图的邻接表中,每个顶点邻接表链接着该顶点所有邻接点。
A .入边B.出边C.入边和出边 D .不是入边也不是出边11.在有向图的逆邻接表中,每个顶点邻接表链接着该顶点所有邻接点。
A .入边B.出边C.入边和出边 D .不是人边也不是出边12.如果从无向图的任一顶点出发进行一次深度优先搜索即可访问所有顶点,则该图一定是A .完全图B.连通图C.有回路 D .一棵树13.采用邻接表存储的图的深度优先遍历算法类似于二叉树的算法。
图习题-数据结构

习题七图一、单项选择题1.设有无向图G=(V,E)和G’=(V’,E’),如G’为G的生成树,则下面不正确的说法是()A.G’为G的子图 B.G’为G的连通分量C.G’为G的极小连通子图且V’=V D.G’是G的无环子图2.任何一个带权的无向连通图的最小生成树()A.只有一棵 B.有一棵或多棵 C.一定有多棵 D.可能不存在3.以下说法正确的是()A.连通分量是无向图中的极小连通子图。
B.强连通分量是有向图中的极大强连通子图。
C.在一个有向图的拓扑序列中,若顶点a在顶点b之前,则图中必有一条弧<a,b>。
D.对有向图G,如果从任意顶点出发进行一次深度优先或广度优先搜索能访问到每个顶点,则该图一定是完全图。
4.图中有关路径的定义是()。
A.由顶点和相邻顶点序偶构成的边所形成的序列 B.由不同顶点所形成的序列C.由不同边所形成的序列 D.上述定义都不是5.设无向图的顶点个数为n,则该图最多有()条边。
A.n-1 B.n(n-1)/2 C. n(n+1)/2 D.0 E.n26.要连通具有n个顶点的有向图,至少需要()条边。
A.n-l B.n C.n+l D.2n7.在一个无向图中,所有顶点的度数之和等于所有边数()倍,在一个有向图中,所有顶点的入度之和等于所有顶点出度之和的()倍。
A.1/2 B.2 C.1 D.48.下列哪一种图的邻接矩阵是对称矩阵?()A.有向图 B.无向图 C.AOV网 D.AOE网9. 下列说法不正确的是()。
A.图的遍历是从给定的源点出发每一个顶点仅被访问一次B.遍历的基本算法有两种:深度遍历和广度遍历C.图的深度遍历不适用于有向图D.图的深度遍历是一个递归过程10.下面哪一方法可以判断出一个有向图是否有环(回路):A.深度优先遍历 B. 拓扑排序 C. 求最短路径 D. 求关键路径11. 在图采用邻接表存储时,求最小生成树的 Prim 算法的时间复杂度为( )。
数据结构 第7章习题答案

第7章 《图》习题参考答案一、单选题(每题1分,共16分)( C )1. 在一个图中,所有顶点的度数之和等于图的边数的 倍。
A .1/2 B. 1 C. 2 D. 4 (B )2. 在一个有向图中,所有顶点的入度之和等于所有顶点的出度之和的 倍。
A .1/2 B. 1 C. 2 D. 4 ( B )3. 有8个结点的无向图最多有 条边。
A .14 B. 28 C. 56 D. 112 ( C )4. 有8个结点的无向连通图最少有 条边。
A .5 B. 6 C. 7 D. 8 ( C )5. 有8个结点的有向完全图有 条边。
A .14 B. 28 C. 56 D. 112 (B )6. 用邻接表表示图进行广度优先遍历时,通常是采用 来实现算法的。
A .栈 B. 队列 C. 树 D. 图 ( A )7. 用邻接表表示图进行深度优先遍历时,通常是采用 来实现算法的。
A .栈 B. 队列 C. 树 D. 图 ()8. 已知图的邻接矩阵,根据算法思想,则从顶点0出发按深度优先遍历的结点序列是( D )9. 已知图的邻接矩阵同上题8,根据算法,则从顶点0出发,按深度优先遍历的结点序列是A . 0 2 4 3 1 5 6 B. 0 1 3 5 6 4 2C. 0 4 2 3 1 6 5D. 0 1 2 34 6 5 ( D )10. 已知图的邻接表如下所示,根据算法,则从顶点0出发按深度优先遍历的结点序列是( A )11. 已知图的邻接表如下所示,根据算法,则从顶点0出发按广度优先遍历的结点序列是A .0 2 4 3 1 5 6B. 0 1 3 6 5 4 2C. 0 1 3 4 2 5 6D. 0 3 6 1 5 4 2⎥⎥⎥⎥⎥⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎢⎢⎢⎢⎢⎣⎡0100011101100001011010110011001000110010011011110A .0 1 3 2 B. 0 2 3 1 C. 0 3 2 1 D. 0 1 2 3(A)12. 深度优先遍历类似于二叉树的A.先序遍历 B. 中序遍历 C. 后序遍历 D. 层次遍历(D)13. 广度优先遍历类似于二叉树的A.先序遍历 B. 中序遍历 C. 后序遍历 D. 层次遍历(A)14. 任何一个无向连通图的最小生成树A.只有一棵 B. 一棵或多棵 C. 一定有多棵 D. 可能不存在(注,生成树不唯一,但最小生成树唯一,即边权之和或树权最小的情况唯一)二、填空题(每空1分,共20分)1. 图有邻接矩阵、邻接表等存储结构,遍历图有深度优先遍历、广度优先遍历等方法。
数据结构习题

图习题(三)
• 1.如图所示是一个无向网图,请分别按Prim 算法和Kruskal算法求最小生成树。
查找习题(一)
1.已知一个有序表为(12,18,24,35,47,50,62,83,90,115,134), 当折半查找值为 90 的元 素时,经过( )次比较后查找成功。 A2 B3 C4 D5 2.已知 10 个元素(54,28,16,73,62,95,60,26,43),按照依次插入 的方法生成一棵二叉排序树,查找值为 62 的结点所需比较次数为( )。 A2 B3 C4 D5 3.已知数据元素为(34,76,45,18,26,54,92,65),按照依次插入结点 的方法生成一棵二叉排序树,则该树的深度为( )。 A4 B5 C6 D7 4.按( )遍历二叉排序树得到的序列是一个有序序列。 A 前序 B 中序 C 后序 D 层次 5.在散列函数 H(k)= k mod m 中,一般来讲,m 应取( )。 A 奇数 B 偶数 C 素数 D 充分大的数
8.设链栈中结点的结构:data为数据域,next为指针域,且top是栈顶指针。若想 在链栈的栈顶插入一个由指针s所指的结点,则应执行下列( )操作。 A.s->next=top->next;top->next=s; B.top->next=s; C.s->next=top;top=top->next; D.s->next=top;top=s;
D.根据元素查找
线性表习题(二)
1.链表相对于顺序表的优点是: 插入、删除 方便。 2.顺序表中访问任意一个结点的时间复杂度均为 O(1) 。 3.在单链表中要在已知结点*P之前插入一个新结点,需找到 *P的直接前趋结点的地址,其查找的时间复杂度为 O(n) 。 4.单链表中需知道 头指针 才能遍历整个链表。 5.在一个长度为n的顺序表中删除第i个元素,要移动 n-i 个元 素。 6.在一个长度为n的顺序表中,如果要在第i个元素前插入一 个元素,要后移 n-i+1 个元素。 7.双链表中,设p是指向其中待删除的结点,则需要执行的操 作为: p->prior->next=p->next 。
数据结构习题

树、图习题一、选择题1 已知一算术表达式的中缀形式为 A+B*C-D/E,后缀形式为ABC*+DE/-,其前缀形式为( )A.-A+B*C/DE B. -A+B*CD/E C.-+*ABC/DE D. -+A*BC/DE2 一个具有1025个结点的二叉树的高h为()A.11 B.10 C.11至1025之间 D.10至1024之间3 二叉树的先序遍历和中序遍历如下:先序遍历:EFHIGJK;中序遍历: HFIEJKG 。
该二叉树根的右子树的根是:()A、 EB、 FC、 GD、 H4 引入二叉线索树的目的是()A.加快查找结点的前驱或后继的速度 B.为了能在二叉树中方便的进行插入与删除C.为了能方便的找到双亲 D.使二叉树的遍历结果唯一5 设森林F中有三棵树,第一,第二,第三棵树的结点个数分别为M1,M2和M3。
与森林F对应的二叉树根结点的右子树上的结点个数是()。
A.M1 B.M1+M2 C.M3 D.M2+M36 有n个叶子的哈夫曼树的结点总数为()。
A.不确定 B.2n C.2n+1 D.2n-17 一个有n个结点的图,最少有()个连通分量,最多有()个连通分量。
A.0 B.1 C.n-1 D.n8 无向图G=(V,E),其中:V={a,b,c,d,e,f},E={(a,b),(a,e),(a,c),(b,e),(c,f),(f,d),(e,d)},对该图进行深度优先遍历,得到的顶点序列正确的是()。
A.a,b,e,c,d,f B.a,c,f,e,b,d C.a,e,b,c,f,d D.a,e,d,f,c,b9 已知有向图G=(V,E),其中V={V1,V2,V3,V4,V5,V6,V7},E={<V1,V2>,<V1,V3>,<V1,V4>,<V2,V5>,<V3,V5>,<V3,V6>,<V4,V6>,<V5,V7>,<V6,V7>},G的拓扑序列是()。
数据结构章节练习题2

第七章图一、选择题1.图中有关路径的定义是()。
A.由顶点和相邻顶点序偶构成的边所形成的序列B.由不同顶点所形成的序列C.由不同边所形成的序列D.上述定义都不是2.设无向图的顶点个数为n,则该图最多有()条边。
A.n-1 B.n(n-1)/2 C.n(n+1)/2 D.0 E.n23.一个n个顶点的连通无向图,其边的个数至少为()。
A.n-1 B.n C.n+1 D.nlogn;4.要连通具有n个顶点的有向图,至少需要()条边。
A.n-l B.n C.n+l D.2n5.一个有n个结点的图,最少有(B )个连通分量,最多有(D )个连通分量。
A.0 B.1 C.n-1 D.n6. 下列说法不正确的是()。
A.图的遍历是从给定的源点出发每一个顶点仅被访问一次C.图的深度遍历不适用于有向图B.遍历的基本算法有两种:深度遍历和广度遍历D.图的深度遍历是一个递归过程7.无向图G=(V,E),其中:V={a,b,c,d,e,f},E={(a,b),(a,e),(a,c),(b,e),(c,f),(f,d),(e,d)},对该图进行深度优先遍历,得到的顶点序列正确的是()。
A.a,b,e,c,d,f B.a,c,f,e,b,d C.a,e,b,c,f,d D.a,e,d,f,c,b8. 在图采用邻接表存储时,求最小生成树的Prim 算法的时间复杂度为( )。
A. O(n)B. O(n+e)C. O(n2)D. O(n3)9. 求解最短路径的Floyd算法的时间复杂度为( )。
A.O(n) B. O(n+c) C. O(n*n)D. O(n*n*n)10.已知有向图G=(V,E),其中V={V1,V2,V3,V4,V5,V6,V7},E={<V1,V2>,<V1,V3>,<V1,V4>,<V2,V5>,<V3,V5>,<V3,V6>,<V4,V6>,<V5,V7>,<V6,V7>},G的拓扑序列是()。
数据结构课后习题答案第七章

第七章图(参考答案)7.1(1)邻接矩阵中非零元素的个数的一半为无向图的边数;(2)A[i][j]= =0为顶点,I 和j无边,否则j和j有边相通;(3)任一顶点I的度是第I行非0元素的个数。
7.2(1)任一顶点间均有通路,故是强连通;(2)简单路径V4 V3 V1 V2;(3)0 1 ∞ 1∞ 0 1 ∞1 ∞ 0 ∞∞∞ 1 0邻接矩阵邻接表(2)从顶点4开始的DFS序列:V5,V3,V4,V6,V2,V1(3)从顶点4开始的BFS序列:V4,V5,V3,V6,V1,V27.4(1)①adjlisttp g; vtxptr i,j; //全程变量② void dfs(vtxptr x)//从顶点x开始深度优先遍历图g。
在遍历中若发现顶点j,则说明顶点i和j间有路径。
{ visited[x]=1; //置访问标记if (y= =j){ found=1;exit(0);}//有通路,退出else { p=g[x].firstarc;//找x的第一邻接点while (p!=null){ k=p->adjvex;if (!visited[k])dfs(k);p=p->nextarc;//下一邻接点}}③ void connect_DFS (adjlisttp g)//基于图的深度优先遍历策略,本算法判断一邻接表为存储结构的图g种,是否存在顶点i //到顶点j的路径。
设 1<=i ,j<=n,i<>j.{ visited[1..n]=0;found=0;scanf (&i,&j);dfs (i);if (found) printf (” 顶点”,i,”和顶点”,j,”有路径”);else printf (” 顶点”,i,”和顶点”,j,”无路径”);}// void connect_DFS(2)宽度优先遍历全程变量,调用函数与(1)相同,下面仅写宽度优先遍历部分。
数据结构习题集第章图

第7章图一、选择题1.一个有n 个顶点的无向图最多有()条边。
A、nB、n(n-1)C、n(n-1)/2D、2n2.具有6 个顶点的无向图至少有()条边才能保证是一个连通图。
A、5B、6C、7D、83.具有n 个顶点且每一对不同的顶点之间都有一条边的图被称为()。
A、线性图B、无向完全图C、无向图D、简单图4.具有4个顶点的无向完全图有()条边。
A、6B、12C、16D、205.G是一个非连通无向图,共有28 条边,则该图至少有()个顶点。
A、6B、7C、8D、96.存储稀疏图的数据结构常用的是()。
A、邻接矩阵B、三元组C、邻接表D、十字链表7.对一个具有n个顶点的图,采用邻接矩阵表示则该矩阵的大小为()。
A、nB、(n-1)2C、(n+1)2D、n28.设连通图G的顶点数为n,则G 的生成树的边数为()。
A、n-1B、nC、2nD、2n-19.对于一个具有N个顶点和E条边的无向图,若采用邻接表表示,则表头向量的大小为((1));所有邻接表中的结点总数是((2))。
(1)A、N B、N+1 C、N-1 D、N+E(2)A、E/2 B、E C、2E D、N+E10.对于一个具有n个顶点和e条边的无向图,若采用邻接表表示,则表向量的大小为(),所有顶点邻接表的结点总数为()。
A、nB、n+1C、n-1D、2nE、e/2F、eG、2eH、n+e11.在有向图的邻接表存储结构中,顶点v在表结点中出现的次数是()。
A、顶点v 的度B、顶点v 的出度C、顶点v 的入度D、依附于顶点v 的边数12.已知一个图,若从顶点a出发进行深度和广度优先搜索遍历,则可能得到的顶点序列分别为()和()(1) A、abecdf B、acfebd C、acebfd D、acfdeb(2) A、abcedf B、abcefd C、abedfc D、acfdeb13.采用邻接表存储的图的深度和广度优先搜索遍历算法类似于二叉树的()和()。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第8章 图8-1 画出1个顶点、2个顶点、3个顶点、4个顶点和5个顶点的无向完全图。
试证明在n 个顶点的无向完全图中,边的条数为n(n-1)/2。
【解答】 【证明】在有n 个顶点的无向完全图中,每一个顶点都有一条边与其它某一顶点相连,所以每一个顶点有n-1条边与其他n-1个顶点相连,总计n 个顶点有n(n-1)条边。
但在无向图中,顶点i 到顶点j 与顶点j 到顶点i 是同一条边,所以总共有n(n-1)/2条边。
8-2 右边的有向图是强连通的吗?请列出所有的简单路径。
【解答】点,它不是强连通的有向图。
各个顶点自成强连通分量。
所谓简单路径是指该路径上没有重复的顶点。
从顶点A 出发,到其他的各个顶点的简单路径有A →B ,A →D →B ,A →B →C ,A →D →B →C ,A →D ,A →B →E ,A →D →E ,A →D →B →E ,A →B →C →F →E ,A →D →B →C →F →E ,A →B →C →F ,A1个顶点的 无向完全图2个顶点的 无向完全图3个顶点的 无向完全图4个顶点的 无向完全图5个顶点的 无向完全图AD⎥⎥⎥⎥⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎢⎢⎢⎢⎣⎡=0100000001001010000010*********Edge →D →B →C →F 。
从顶点B 出发,到其他各个顶点的简单路径有B →C ,B →C →F ,B →E ,B →C →F →E 。
从顶点C 出发,到其他各个顶点的简单路径有C →F ,C →F →E 。
从顶点D 出发,到其他各个顶点的简单路径有D →B ,D →B →C ,D →B →C →F ,D →E ,D →B →E ,D →B →C →F →E 。
从顶点E 出发,到其他各个顶点的简单路径无。
从顶点F 出发,到其他各个顶点的简单路径有F →E 。
8-3 给出右图的邻接矩阵、邻接表和邻接多重表表示。
【解答】(1) 邻接矩阵A D(2) 邻接表(3) 邻接多重表(十字链表)123450 1 2 3 4 5∧(出边表)(入边表)12345data fin fouti j ilink jlink(A, B)(A, D)(B, C)8-4 用邻接矩阵表示图时,若图中有1000个顶点,1000条边,则形成的邻接矩阵有多少矩阵元素?有多少非零元素?是否稀疏矩阵? 【解答】一个图中有1000个顶点,其邻接矩阵中的矩阵元素有10002 = 1000000个。
它有1000个非零元素(对于有向图)或2000个非零元素(对于无向图),因此是稀疏矩阵。
8-5 用邻接矩阵表示图时,矩阵元素的个数与顶点个数是否相关?与边的条数是否相关? 【解答】用邻接矩阵表示图,矩阵元素的个数是顶点个数的平方,与边的条数无关。
矩阵中非零元素的个数与边的条数有关。
8-6 有n 个顶点的无向连通图至少有多少条边?有n 个顶点的有向强连通图至少有多少条边?试举例说明。
(B, E)(C, F)(D, B)(D, E)(F, E)①②③或①②③①②③④⑤【解答】n个顶点的无向连通图至少有n-1条边,n个顶点的有向强连通图至少有n条边。
例如:特例情况是当n = 1时,此时至少有0条边。
8-7对于有n个顶点的无向图,采用邻接矩阵表示,如何判断以下问题:图中有多少条边?任意两个顶点i和j之间是否有边相连?任意一个顶点的度是多少?【解答】用邻接矩阵表示无向图时,因为是对称矩阵,对矩阵的上三角部分或下三角部分检测一遍,统计其中的非零元素个数,就是图中的边数。
如果邻接矩阵中A[i][j] 不为零,说明顶点i与顶点j之间有边相连。
此外统计矩阵第i行或第i列的非零元素个数,就可得到顶点i的度数。
8-8对于如右图所示的有向图,试写出:(1) 从顶点①出发进行深度优先搜索所得到的深度优先生成树;(2) 从顶点②出发进行广度优先搜索所得到的广度优先生成树;【解答】(1) 以顶点①为根的深度优先生成树(不唯一):②③④⑤⑥④⑤④⑤(2) 以顶点②为根的广度优先生成树:①②③④⑤8-9 试扩充深度优先搜索算法,在遍历图的过程中建立生成森林的左子女-右兄弟链表。
算法的首部为void Graph::DFS ( const int v, int visited [ ], TreeNode<int> * t ) 其中,指针t指向生成森林上具有图顶点v信息的根结点。
(提示:在继续按深度方向从根v的某一未访问过的邻接顶点w向下遍历之前,建立子女结点。
但需要判断是作为根的第一个子女还是作为其子女的右兄弟链入生成树。
)【解答】为建立生成森林,需要先给出建立生成树的算法,然后再在遍历图的过程中,通过一次次地调用这个算法,以建立生成森林。
te mplate<Type> void Graph<Type> :: DFS_Tree ( const int v, int visited [ ], TreeNode<Type> *t ) { //从图的顶点v出发, 深度优先遍历图, 建立以t (已在上层算法中建立)为根的生成树。
Visited[v] = 1; int first = 1; TreeNode<Type> * p, * q;int w = GetFirstNeighbor ( v );//取第一个邻接顶点while ( w != -1 ) {//若邻接顶点存在if ( vosited[w] == 0 ) { //且该邻接结点未访问过p = new TreeNode<Type> ( GetValue (w) );//建立新的生成树结点if ( first == 1 ) //若根*t还未链入任一子女{ t->setFirstChild ( p );first = 0; }//新结点*p成为根*t的第一个子女else q->setNextSibling ( p );//否则新结点*p成为*q的下一个兄弟q = p;//指针q总指示兄弟链最后一个结点DFS_Tree ( w, visited, q );//从*q向下建立子树}w = GetNextNeighbor ( v, w );//取顶点v排在邻接顶点w的下一个邻接顶点}}下一个算法用于建立以左子女-右兄弟链表为存储表示的生成森林。
template<Type> void Graph<Type> :: DFS_Forest ( Tree<Type>& T ) {//从图的顶点v出发, 深度优先遍历图, 建立以左子女-右兄弟链表表示的生成森林T。
T.root = NULL; int n =NumberOfVertices ( ); //顶点个数TreeNode<Type> * p, * q;int * visited = new int [ n ];//建立访问标记数组for ( int v = 0; v < n; v++ ) visited[v] = 0;for ( v = 0; v < n; v++ ) //逐个顶点检测if ( visited[v] == 0 ) {//若尚未访问过p = new TreeNode<Type> ( GetValue ( v ) );//建立新结点*pif ( T.root == NULL ) T.root = p;//原来是空的生成森林, 新结点成为根else q-> setNextSibling ( p );//否则新结点*p成为*q的下一个兄弟q = p;DFS_Tree ( v, visited, p );//建立以*p为根的生成树}}8-10 用邻接表表示图时,顶点个数设为n,边的条数设为e,在邻接表上执行有关图的遍历操作时,时间代价是O(n*e)?还是O(n+e)?或者是O(max(n,e))?【解答】在邻接表上执行图的遍历操作时,需要对邻接表中所有的边链表中的结点访问一次,还需要对所有的顶点访问一次,所以时间代价是O(n+e)。
8-11 右图是一个连通图,请画出(1) 以顶点①为根的深度优先生成树;(2) 如果有关节点,请找出所有的关节点。
(3)如果想把该连通图变成重连通图,至少在图中加几条边?⑩①②③④⑤⑥⑦⑧⑨如何加?【解答】(1) 以顶点①为根的深度优先生成树:(2) 关节点为 ①,②,③,⑦,⑧(3) 至少加四条边 (1, 10), (3, 4), (4, 5), (5, 6)。
从③的子孙结点⑩到③的祖先结点①引一条边,从②的子孙结点④到根①的另一分支③引一条边,并将⑦的子孙结点⑤、⑥与结点④连结起来,可使其变为重连通图。
8-12试证明在一个有n 个顶点的完全图中,生成树的数目至少有2n-1-1。
【证明】略8-13 编写一个完整的程序,首先定义堆和并查集的结构类型和相关操作,再定义Kruskal 求连通网络的最小生成树算法的实现。
并以右图为例,写出求解过程中堆、并查集和最小生成①② ③④ ⑤⑥11 768510 97⑩ ①② ③④ ⑤⑥⑦⑧⑨⑩ ①② ③④ ⑤⑥⑦⑧⑨树的变化。
【解答】求解过程的第一步是对所有的边,按其权值大小建堆:1 3 112 3 102 4 9 23 101 3 111 2 72 3 102 4 9加(1, 2), (1, 3),(2,3)加(2, 4) 加(3, 4)1 3 112 4 9 23 101 3 112 4 92 3 103 6 8加(3, 5) 加(3, 6)1 2 7 2 4 9 2 3 10 3 6 81 3 11加(5, 6)求解过程中并查集与堆的变化:最后得到的生成树如下3 1 -6 3 3 51 3 113 5 72 4 92 3 103 6 8①③⑤67579③④1 3 111 2 7 3 5 72 4 9 23 10 3 6 8选(3,4,5)③④⑤⑥选(5,6,6) 1 3 113 5 72 4 9 23 103 6 8③④⑤⑥选(1,2,7)①②③④⑤⑥选(3,5,7)①②1 3 112 4 9 23 103 6 8③④⑤⑥选(3,6,8), 在同一连通分量上, 不加①② 1 3 11 2 3 102 4 9 ③④⑤⑥选(2,4,9), 结束①②1 3 112 3 100 1 2 3 4 5 6并查集的存储表示②④⑥完整的程序如下:#include <iostream.h>template <class Type> class MinHeap {public:enum { MaxHeapSize = 50 };MinHeap ( int Maxsize = MaxHeapSize );MinHeap ( Type Array[ ], int n );void Insert ( const Type &ele );void RemoveMin ( Type &Min );void Output ();private:void FilterDown ( int start, int end );void FilterUp ( int end );Type *pHeap;int HMaxSize;int CurrentSize;};class UFSets {public:enum { MaxUnionSize = 50 };UFSets ( int MaxSize = MaxUnionSize );~UFSets () { delete [ ] m_pParent; }void Union ( int Root1, int Root2 );int Find ( int x );private:int m_iSize;int *m_pParent;};class Graph {public:enum { MaxVerticesNum = 50 };Graph( int Vertices = 0) { CurrentVertices = Vertices; InitGraph(); } void InitGraph ();void Kruskal ();int GetVerticesNum () { return CurrentVertices; }private:int Edge[MaxVerticesNum][MaxVerticesNum];int CurrentVertices;};class GraphEdge {public:int head, tail;int cost;int operator <= ( GraphEdge &ed );};GraphEdge :: operator <= ( GraphEdge &ed ) {return this->cost <= ed.cost;}UFSets :: UFSets ( int MaxSize ) {m_iSize = MaxSize;m_pParent = new int[m_iSize];for ( int i = 0; i < m_iSize; i++ ) m_pParent[i] = -1;}void UFSets :: Union ( int Root1, int Root2 ) {m_pParent[Root2] = Root1;}int UFSets :: Find ( int x ) {while ( m_pParent[x] >= 0 ) x = m_pParent[x];return x;}template <class Type> MinHeap<Type> :: MinHeap ( int Maxsize ) { HMaxSize = Maxsize;pHeap = new Type[HMaxSize];CurrentSize = -1;}template <class Type> MinHeap<Type> :: MinHeap ( Type Array[], int n ) { HMaxSize = ( n < MaxHeapSize ) ? MaxHeapSize : n;pHeap = new Type[HMaxSize];for ( int i = 0; i < n; i++ ) pHeap[i] = Array[i];CurrentSize = n-1;int iPos = ( CurrentSize - 1 ) / 2;while ( iPos >= 0 ) {FilterDown ( iPos, CurrentSize );iPos--;}}template <class Type> void MinHeap<Type> :: FilterDown ( int start, int end ) { int i = start, j = 2 * start + 1;Type Temp = pHeap[i];while ( j <= end ) {if ( j < end && pHeap[j+1] <= pHeap[j] ) j++;if ( Temp <= pHeap[j] ) break;pHeap[i] = pHeap[j];i = j; j = 2 * j + 1;}pHeap[i] = Temp;}template <class Type> void MinHeap<Type> :: FilterUp ( int end ) { int i = end, j = ( end - 1 ) / 2;Type Temp = pHeap[i];while ( i > 0 ) {if ( pHeap[j] <= Temp ) break;pHeap[i] = pHeap[j];i = j; j = ( j - 1 ) / 2;}pHeap[i] = Temp;}template <class Type> void MinHeap<Type> :: Insert ( const Type &ele ) { CurrentSize++;if ( CurrentSize == HMaxSize ) return;pHeap[CurrentSize] = ele;FilterUp ( CurrentSize );}template <class Type> void MinHeap<Type> :: RemoveMin ( Type &Min ) { if ( CurrentSize < 0 )return;Min = pHeap[0];pHeap[0] = pHeap[CurrentSize--];FilterDown ( 0, CurrentSize );}template <class Type> void MinHeap<Type> :: Output ( ) {for ( int i = 0; i <= CurrentSize; i++ ) cout << pHeap[i] << " ";cout << endl;}void Graph :: InitGraph( ) {Edge[0][0] = -1;Edge[0][1] = 28;Edge[0][2] = -1;Edge[0][3] = -1;Edge[0][4] = -1;Edge[0][5] = 10;Edge[0][6] = -1;Edge[1][1] = -1;Edge[1][2] = 16;Edge[1][3] = -1;Edge[1][4] = -1;Edge[1][5] = -1;Edge[1][6] = 14;Edge[2][2] = -1; Edge[2][3] = 12;Edge[2][4] = -1; Edge[2][5] = -1;Edge[2][6] = -1;Edge[3][3] = -1;Edge[3][4] = 22;Edge[3][5] = -1;Edge[3][6] = 18;Edge[4][4] = -1;Edge[4][5] = 25; Edge[4][6] = 24;Edge[5][5] = -1;Edge[5][6] = -1;Edge[6][6] = -1;for ( int i = 1; i < 6; i++ )for ( int j = 0; j < i; j ++ ) Edge[i][j] = Edge[j][i];}void Graph :: Kruskal( ) {GraphEdge e;int VerticesNum = GetVerticesNum ( );int i, j, count;MinHeap<GraphEdge> heap ( VerticesNum *VerticesNum );UFSets set ( VerticesNum );for ( i = 0; i < VerticesNum; i++ )for ( j = i + 1; j < VerticesNum; j++ )if ( Edge[i][j] > 0 ) {e.head = i; e.tail = j; e.cost = Edge[i][j];heap.Insert ( e );}count = 1;while ( count < VerticesNum ) {heap.RemoveMin ( e );i = set.Find ( e.head );j = set.Find ( e.tail );if ( i != j ) {set.Union ( i, j );count++;cout << "( " << e.head << ", " << e.tail << ", " << e.cost << " )" << endl;}}}8-14 利用Dijkstra 算法的思想,设计一个求最小生成树的算法。