最小生成树经典算法

合集下载

最小生成树及算法

最小生成树及算法

|S|=n-1, 说明是树 最后S={a1, a2, a3,… ,an-1}
B. 破圈法
算法2 步骤如下: (1) 从图G中任选一棵树T1. (2) 加上一条弦e1,T1+e1中 生成一个圈. 去掉此圈中最大权边,得到新树T2, 以T2代T1,重复(2)再检查剩余的弦,直到全部弦 检查完毕为止.
例 n个城市,各城市之间的距离如下表(距离为 ∞,表示两个城市之间没有直接到达的线路)。 从一个城市出发走遍各个城市,如何选择最优的 旅行路线.
性质 任何一棵树至少有两片树叶。 证明 设树T=(V,E),结点数为v,因T是连通的,因 此,树中每个结点vi,有deg(vi)1,且 deg(vi)=2(v-1)=2v-2. 若T中结点度数都大于2,则 deg(vi) 2v,矛盾。 若T中只有一个结点度数为1,则 deg(vi) 2(v-1)+1=2v-1 矛盾。
4 3
v5 3 v6
3.5 生成树的计数
1、一些概念 • • ① 设 G 是一个连通图。 T , T 分别是 G 的两个生成树,如果 E (T ) E (T ) ,则认为 T , T 是 G 的两个不同的生成树。 G 的 不同的生成树个数用 (G) 表示。 如:
v1 v3 v2 v3 v1 v2 v3 v1 v2 v3 v1 v2
证明:⑴⑵ 当 n=2时, e=1, 显然 e=n-1. 假设n=k-1时命题成立,当n=k时,因G无圈、连 通,则至少有一条边(u,v),deg(u)=1,删去u,得到 连通无圈的图G1, G1的边数e1,结点数n1满足: e1=n1-1= k-2 将u,边(u,v)加到 G1中,得到T,且 e=n-1.
( K3 ) 3。 则:
② G-e: 从G中去掉边e后所得的图。

用破圈法求最小生成树的算法

用破圈法求最小生成树的算法

用破圈法求最小生成树的算法
求最小生成树是搜索树上每条边将权值加起来最小的那棵树,也就是要
求在给定顶点的一组边的条件下求出最小的生成树,一般采用贪心算法来求解。

其中最常用的算法就是破圈法。

破圈法实质上是 Prim 算法的改进,是一种贪心算法。

它的基本思想是:试着将边依次加入最小生成树中,当已生成的最小生成树中的边形成了一个
环的时候,其中的边中权值最大的一条被舍弃,存在于两个不同的顶点间。

破圈法求最小生成树算法基本步骤如下:
1.初始化最小生成树,构造一个空集合;
2.从贴源点开始,找出所有连接源点的边中权值最小的增加一条边到空集合中;
3.重复上述步骤,在剩余边权中选出最小值,增加一条边,并保证了加入当
前边后不产生环;
4.当把所有边都添加到集合中,即得到最小生成树;
破圈法的复杂度是O(n^2),由于它具有简单的求解过程和易于实现的特性,因而得到广泛的应用。

破圈法非常适合在网络中采用,它可以容易的获
得一条路径的最小权值生成树从而实现网络的最佳路径匹配。

破圈法可以证明:当每一条边都属于给定顶点集合时,最小生成树一定
存在。

因此它在可以用来求解最小生成树的问题中是非常有效的。

最小生成树的算法

最小生成树的算法

最小生成树的算法王洁引言:求连通图的最小生成树是数据结构中讨论的一个重要问题.在现实生活中,经常遇到如何得到连通图的最小生成树,求最小生成树不仅是图论的基本问题之一 ,在实际工作中也有很重要的意义,,人们总想寻找最经济的方法将一个终端集合通过某种方式将其连接起来 ,比如将多个城市连为公路网络 ,要设计最短的公路路线;为了解决若干居民点供水问题 ,要设计最短的自来水管路线等.而避开这些问题的实际意义 ,抓住它们的数学本质 ,就表现为最小生成树的构造。

下面将介绍几种最小生成树的算法。

一,用“破圈法”求全部最小生成树的算法1 理论根据1.1 约化原则给定一无向连通图 G =(V ,E )( V 表示顶点,E 表示边),其中 V={ 1v , 2v ,3v …… n v },E= { 1e , 2e , 3e …… n e }对于 G 中的每条边 e ∈ E 都赋予权ω(i e )>0,求生成树 T = (V ,H ),H ⊆ E ,使生成树所有边权最小,此生成树称为最小生成树.(1) 基本回路将属于生成树 T 中的边称为树枝,树枝数为n -1,不属于生成树的边称为连枝.将任一连枝加到生成树上后都会形成一条回路.把这种回路称为基本回路,记为()cf e 。

基本回路是由 T 中的树枝和一条连枝构成的回路.(2) 基本割集设无向图 G 的割集 S (割集是把连通图分成两个分离部分的最少支路集合) ,若 S 中仅包含有T 中的一条树枝,则称此割集为基本割集,记为()S e 。

基本割集是集合中的元素只有一条是树枝,其他的为连枝.(3) 等长变换设T=(V,H),为一棵生成树,e ∈ H, 'e ∈ E, 'e ∉ H,当且仅当'e ∈()cf e ,也就是说e ∈()S e ,则'T =T ⊕{e, 'e }也是一棵生成树。

当()e ω='()e ω时,这棵生成树叫做等长变换。

最小生成树---普里姆算法(Prim算法)和克鲁斯卡尔算法(Kruskal算法)

最小生成树---普里姆算法(Prim算法)和克鲁斯卡尔算法(Kruskal算法)

最⼩⽣成树---普⾥姆算法(Prim算法)和克鲁斯卡尔算法(Kruskal算法)最⼩⽣成树的性质:MST性质(假设N=(V,{E})是⼀个连通⽹,U是顶点集V的⼀个⾮空⼦集,如果(u,v)是⼀条具有最⼩权值的边,其中u属于U,v属于V-U,则必定存在⼀颗包含边(u,v)的最⼩⽣成树)普⾥姆算法(Prim算法)思路:以点为⽬标构建最⼩⽣成树1.将初始点顶点u加⼊U中,初始化集合V-U中各顶点到初始顶点u的权值;2.根据最⼩⽣成树的定义:从n个顶点中,找出 n - 1条连线,使得各边权值最⼩。

循环n-1次如下操作:(1)从数组lowcost[k]中找到vk到集合U的最⼩权值边,并从数组arjvex[k] = j中找到该边在集合U中的顶点下标(2)打印此边,并将vk加⼊U中。

(3)通过查找邻接矩阵Vk⾏的各个权值,即vk点到V-U中各顶点的权值,与lowcost的对应值进⾏⽐较,若更⼩则更新lowcost,并将k存⼊arjvex数组中以下图为例#include<bits/stdc++.h>using namespace std;#define MAXVEX 100#define INF 65535typedef char VertexType;typedef int EdgeType;typedef struct {VertexType vexs[MAXVEX];EdgeType arc[MAXVEX][MAXVEX];int numVertexes, numEdges;}MGraph;void CreateMGraph(MGraph *G) {int m, n, w; //vm-vn的权重wscanf("%d %d", &G->numVertexes, &G->numEdges);for(int i = 0; i < G->numVertexes; i++) {getchar();scanf("%c", &G->vexs[i]);}for(int i = 0; i < G->numVertexes; i++) {for(int j = 0; j < G->numVertexes; j++) {if(i == j) G->arc[i][j] = 0;else G->arc[i][j] = INF;}}for(int k = 0; k < G->numEdges; k++) {scanf("%d %d %d", &m, &n, &w);G->arc[m][n] = w;G->arc[n][m] = G->arc[m][n];}}void MiniSpanTree_Prim(MGraph G) {int min, j, k;int arjvex[MAXVEX]; //最⼩边在 U集合中的那个顶点的下标int lowcost[MAXVEX]; // 最⼩边上的权值//初始化,从点 V0开始找最⼩⽣成树Tarjvex[0] = 0; //arjvex[i] = j表⽰ V-U中集合中的 Vi点的最⼩边在U集合中的点为 Vjlowcost[0] = 0; //lowcost[i] = 0表⽰将点Vi纳⼊集合 U ,lowcost[i] = w表⽰ V-U中 Vi点到 U的最⼩权值for(int i = 1; i < G.numVertexes; i++) {lowcost[i] = G.arc[0][i];arjvex[i] = 0;}//根据最⼩⽣成树的定义:从n个顶点中,找出 n - 1条连线,使得各边权值最⼩for(int i = 1; i < G.numVertexes; i++) {min = INF, j = 1, k = 0;//寻找 V-U到 U的最⼩权值minfor(j; j < G.numVertexes; j++) {// lowcost[j] != 0保证顶点在 V-U中,⽤k记录此时的最⼩权值边在 V-U中顶点的下标if(lowcost[j] != 0 && lowcost[j] < min) {min = lowcost[j];k = j;}}}printf("V[%d]-V[%d] weight = %d\n", arjvex[k], k, min);lowcost[k] = 0; //表⽰将Vk纳⼊ U//查找邻接矩阵Vk⾏的各个权值,与lowcost的对应值进⾏⽐较,若更⼩则更新lowcost,并将k存⼊arjvex数组中for(int i = 1; i < G.numVertexes; i++) {if(lowcost[i] != 0 && G.arc[k][i] < lowcost[i]) {lowcost[i] = G.arc[k][i];arjvex[i] = k;}}}int main() {MGraph *G = (MGraph *)malloc(sizeof(MGraph));CreateMGraph(G);MiniSpanTree_Prim(*G);}/*input:4 5abcd0 1 20 2 20 3 71 2 42 3 8output:V[0]-V[1] weight = 2V[0]-V[2] weight = 2V[0]-V[3] weight = 7最⼩总权值: 11*/时间复杂度O(n^2)克鲁斯卡尔算法(Kruskal算法)思路:以边为⽬标进⾏构建最⼩⽣成树在边集中依次寻找最⼩权值边,若构建是不形成环路(利⽤parent数组记录各点的连通分量),则将其添加到最⼩⽣成树中。

曼哈顿距离最小生成树

曼哈顿距离最小生成树

曼哈顿距离最小生成树曼哈顿距离最小生成树(ManhattanMinimumSpanningTree)是一种在多维空间(N维空间)里寻找最小代价连接任何两个点的有效算法。

它使用曼哈顿距离作为代价并且能够在多维空间中解决最短路径问题。

曼哈顿距离是一种特殊的距离度量,用来测量在一个N维空间中任意两点之间的距离。

它能够很好地表达在有权重约束的多维空间中任意点之间的最短路径。

曼哈顿距离最小生成树以贪心算法的形式实现,能够有效地解决多维空间中的最短路径问题。

它的核心思想是从一个现有的最小生成树开始,不断的增加新的元素来加强和扩展树的结构。

曼哈顿距离最小生成树的基本步骤如下:(1)从空树开始,任意选取一个节点作为初始节点。

(2)以曼哈顿距离为标准,从剩余的n-1个节点中找出与初始节点距离较近的节点,从而构成一个最小生成树。

(3)重复步骤(2),直至最小生成树中包含所有节点,此时得到了一颗曼哈顿距离最小生成树。

曼哈顿距离最小生成树的一个重要特性是它有一个非常直接的应用:它能够帮助我们解决计算最短路径的问题,也就是计算从某个固定起点到任意终点的最短路径。

使用曼哈顿距离最小生成树来计算最短路径的过程如下:(1)先构造一颗曼哈顿距离最小生成树。

(2)对最小生成树中每条边计算曼哈顿距离,并保存到一个表中。

(3)对最小生成树中每个节点,根据曼哈顿距离计算出从起点到该节点的最短距离,并保存到一个表中。

(4)搜索表中最短路径,找到从起点到终点的最短路径,也就是从起点到终点的最短路径。

曼哈顿距离最小生成树在多维空间中解决最短路径问题时,具有非常强大的功能。

它能够快速、高效地找到任意两点之间的最短路径,而无需考虑权重的约束。

这样,它就成为了一种非常有效的最小代价连接算法,在多维空间中广泛应用。

总的来说,曼哈顿距离最小生成树是在多维空间中解决最短路径问题的一种经典算法。

它使用曼哈顿距离作为代价,能够快速、高效地找到任意两点之间的最短路径,而无需考虑权重的约束。

克鲁斯卡尔算法求最小生成树完整代码

克鲁斯卡尔算法求最小生成树完整代码

克鲁斯卡尔算法是一种用来求解最小生成树(Minimum Spanning Tree)的经典算法,它采用了贪心策略,能够高效地找到图中的最小生成树。

下面将为大家介绍克鲁斯卡尔算法的完整代码,希望对大家有所帮助。

1. 算法思路克鲁斯卡尔算法的基本思路是:首先将图中的所有边按照权值进行排序,然后从小到大依次考虑每条边,如果加入该边不会构成环,则将其加入最小生成树中。

在算法执行过程中,我们需要使用并查集来判断是否会构成环。

2. 代码实现接下来,我们将给出克鲁斯卡尔算法的完整代码,代码使用C++语言编写,具体如下:```cpp#include <iostream>#include <vector>#include <algorithm>using namespace std;// 定义图的边struct Edge {int u, v, weight;Edge(int u, int v, int weight) : u(u), v(v), weight(weight) {} };// 定义并查集class UnionFind {private:vector<int> parent;public:UnionFind(int n) {parent.resize(n);for (int i = 0; i < n; i++) {parent[i] = i;}}int find(int x) {if (parent[x] != x) {parent[x] = find(parent[x]);}return parent[x];}void Union(int x, int y) {int root_x = find(x);int root_y = find(y);if (root_x != root_y) {parent[root_x] = root_y;}}};// 定义比较函数用于排序bool cmp(const Edge a, const Edge b) {return a.weight < b.weight;}// 克鲁斯卡尔算法vector<Edge> kruskal(vector<Edge> edges, int n) { // 先对边进行排序sort(edges.begin(), edges.end(), cmp);// 初始化最小生成树的边集vector<Edge> res;UnionFind uf(n);for (int i = 0; i < edges.size(); i++) {int u = edges[i].u, v = edges[i].v, weight = edges[i].weight; // 判断是否构成环if (uf.find(u) != uf.find(v)) {uf.Union(u, v);res.push_back(edges[i]);}}return res;}// 测试函数int m本人n() {vector<Edge> edges;edges.push_back(Edge(0, 1, 4));edges.push_back(Edge(0, 7, 8));edges.push_back(Edge(1, 2, 8));edges.push_back(Edge(1, 7, 11));edges.push_back(Edge(2, 3, 7));edges.push_back(Edge(2, 5, 4));edges.push_back(Edge(2, 8, 2));edges.push_back(Edge(3, 4, 9));edges.push_back(Edge(3, 5, 14));edges.push_back(Edge(4, 5, 10));edges.push_back(Edge(5, 6, 2));edges.push_back(Edge(6, 7, 1));edges.push_back(Edge(6, 8, 6));edges.push_back(Edge(7, 8, 7));vector<Edge> res = kruskal(edges, 9);for (int i = 0; i < res.size(); i++) {cout << res[i].u << " " << res[i].v << " " << res[i].weight << endl;}return 0;}```3. 算法实例上述代码实现了克鲁斯卡尔算法,并对给定的图进行了最小生成树的求解。

最小生成树的模型数学公式

最小生成树的模型数学公式

最小生成树的模型数学公式
最小生成树的模型数学公式是:
给定无向连通图G(V,E),其中V为图的顶点集合,E为图的边集合。

每条边e∈E都带有一个非负权重w(e)。

找到一个包含图中所有顶点的子图T(V,E'),使得E' ⊆ E,并且E'构成一颗树(即连通且无环),使得所有的边的权重之和最小。

拓展:
最小生成树的应用十分广泛,可以用于解决多种问题。

以下是最小生成树的一些常见拓展场景:
1.带有约束条件的最小生成树:
在某些情况下,除了最小化权重之和外,还需要满足一些特定的约束条件。

例如,可以要求最小生成树的边数限制在特定的范围内,或者要求选择特定类型的边。

这时可以在最小生成树的模型中引入额外的约束条件,从而得到满足要求的最小生成树。

2.多目标最小生成树:
有时候,最小生成树问题不仅需要最小化权重之和,还需要考虑其他目标。

例如,可以同时考虑最小化权重之和和最大化生成树中的最长边权重。

这样的问题可以转化为多目标优化问题,并通过权衡不同目标之间的关系来求解。

3.带有边权重动态变化的最小生成树:
在某些场景中,图的边权重可能会根据一些规则进行动态变化。

例如,网络中的通信链路可能会根据网络拓扑和负载情况进行变化。

这时可以通过动态更新最小生成树来快速适应环境变化,从而保持最小生成树的有效性。

总之,最小生成树的模型可以通过引入不同的约束条件和目标函数进行拓展,以适应不同的应用场景。

克里斯卡尔算法最小生成树

克里斯卡尔算法最小生成树

克里斯卡尔算法最小生成树什么是克里斯卡尔算法?克里斯卡尔算法是一种求解最小生成树(Minimum Spanning Tree, MST)的算法,它采用贪心算法的思想,在给定一个连通图的情况下,通过逐步选择边来生成树,最终得到权值和最小的生成树。

为了更好地理解克里斯卡尔算法,我们首先要明确最小生成树的概念。

在一个连通图中,最小生成树是指连接图中所有顶点的树,并且树上所有边的权值之和最小。

生成树是一个无环的连通图,具有n个顶点的连通图的生成树必然含有n-1条边。

克里斯卡尔算法的步骤如下:1. 初始化:将图中的每个顶点看作是一个单独的树,每个树只包含一个节点。

同时,创建一个空的边集合用于存储最小生成树的边。

2. 对所有边按照权值进行升序排列。

3. 依次选择权值最小的边,并判断该边连接的两个节点是否属于不同的树(不属于同一个连通分量)。

4. 如果两个节点不属于同一个树,则将这条边添加到边集合中,并将两个节点合并为同一个连通分量。

5. 重复步骤3和步骤4,直到最小生成树的边数达到n-1条为止。

6. 返回边集合,即为最小生成树。

通过这个步骤的执行,克里斯卡尔算法能够保证运行过程中生成的树权值和是最小的。

这是因为在选择边时,我们总是选择权值最小且不会形成环路的边,这样生成的树就不会包含多余的边。

需要注意的是,克里斯卡尔算法适用于带权无向连通图,如果是带权有向图,需要先进行转化为无向图的操作。

另外,克里斯卡尔算法在实际应用中有着广泛的应用,比如网络设计、电路设计以及地图路线规划等领域。

总结一下,克里斯卡尔算法是一种通过贪心思想解决最小生成树问题的算法。

它通过逐步选择权值最小的边,并将不同的树合并为一个连通分量的方式,生成一个权值和最小的生成树。

在实际应用中,克里斯卡尔算法具有重要的意义,能够为我们提供高效、经济的解决方案。

通过了解和学习克里斯卡尔算法,我们能够更好地理解图论中的最小生成树问题,并运用其解决实际问题。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

最小生成树的两种经典算法的分析及实现摘要:数据结构是计算机科学的算法理论基础和软件设计的技术基础,在计算机领域中有着举足轻重的作用,是计算机学科的核心课程。

构造最小生成树有很多算法,本文主要介绍了图的概念、图的遍历,并分析了PRIM和KRUSKAL的两种经典算法的算法思想,对两者进行了详细的比较,最后用这两种经典算法实现了最小生成树的生成。

关键词:连通图,赋权图,最小生成树,算法,实现1 前言假设要在n个城市之间建立通信联络网,则连接n个城市只需要n-1条线路。

这时,自然会考虑这样一个问题,如何在节省费用的前提下建立这个通信网?自然在每两个城市之间都可以设置一条线路,而这相应的就要付出较高的经济代价。

n个城市之间最多可以设置n (n-1)/2条线路,那么如何在这些可能的线路中选择n-1 条使总的代价最小呢?可以用连通网来表示n 个城市以及n个城市之间可能设置的通信线路,其中网的顶点表示城市,边表示两个城市之间的线路,赋予边的权值表示相应的代价。

对于n个顶点的连通网可以建立许多不同的生成树,每一个生成树都可以是一个通信网。

现在要选择这样一棵生成树,也就是使总的代价最小。

这个问题便是构造连通网的最小代价生成树(简称最小生成树)的问题。

一棵生成树的代价就是树上各边的代价之和。

2图的概念2.1 定义无序积在无序积中,无向图,其中为顶点(结点)集,为边集,,中元素为无向边,简称边。

有向图,其中为顶点(结点)集,为边集,,中元素为有向边,简称边。

有时,泛指有向图或无向图。

2.2 图的表示法有向图,无向图的顶点都用小圆圈表示。

无向边——连接顶点的线段。

有向边——以为始点,以为终点的有向线段。

2.3 概念(1)有限图——都是有限集的图。

阶图——的图。

零图——的图。

特别,若又有,称平凡图。

(2)关联 (边与点关系)——设边(或),则称与(或)关联。

无环孤立点——无边关联的点。

环——一条边关联的两个顶点重合,称此边为环 (即两顶点重合的边)。

悬挂点——只有一条边与其关联的点,所对应的边叫悬挂边。

(3)平行边——关联于同一对顶点的若干条边称为平行边。

平行边的条数称为重数。

多重图——含有平行边的图。

简单图——不含平行边和环的图。

2.4 完全图设为阶无向简单图,若中每个顶点都与其余个顶点相邻,则称为阶无向完全图,记作。

若有向图的任一对顶点,既有有向边,又有有向边,则称为有向完全图。

例如:3 图的遍历从图中某一顶点出发访遍图中其余顶点,且使每一顶点仅被访问一次。

这一过程叫做图的遍历。

遍历图的基本方法有两种:深度优先搜索和广度优先搜索。

这两种方法都适用于有向图和无向图。

和树的遍历类似,图的遍历也是从某个顶点出发,沿着某条边搜索路径对图中所有顶点各作一次访问。

若给定的图是连通图,则从图中任意顶点出发顺着边可以访问到该图中所有的顶点,然而,图的遍历比树的遍历复杂得多,这是因为图中的任一点都可能和其余顶点相邻接,故在访问了某个顶点之后,可能顺着某条回路又到了该顶点。

为了避免重复访问同一个顶点,必须记住每个顶点是否被访问过。

为此,可设置一个布尔向量visited[1..n],它的初值为false,一旦访问了顶点vi,便将visited[i]置为ture。

3.1基本概念和定理定义定义1:图G=(V,U)的弧列u=(uu..u ) 叫做一个链;把端点重合的链叫做圈,也叫做回路。

定义2:不包含圈的图称为无圈图,连通的无圈图称为树,用符号T 来表示。

定理1:在一棵树中每一对点之间只有一条路径。

定理2:有n个点的一棵树有n-1条边。

定义3:如果一棵树T 为一个连通图的子图,且包括G 中所有的点,则称该树为G 的生成树。

定义4:对每条边e,可赋以一个实数ω(e),称为e的权,G连同它边上的权称为赋权图。

定义5:在一个加权图中一棵生成树T 的权是T 中各个树枝的权之和,一般而言,加权图G 中不同的生成树将有不同的权,G 的所有生成树中,权最小的那棵生成树称为G的最小生成树,或称为G 的最优生成树。

3.2 连通图的深度优先搜索连通图深度优先搜索的基本思想如下:假定图中某个顶点v1为出发点,首先访问出发点v1,然后任选一个v1的访问过的邻接点v2,以v2为新的出发点继续进行深度优先搜索,直至图中所有顶点被访问过。

显然,图的深度优先搜索是一个递归过程,类似于树的前序遍历,它的特点是尽可能先对纵深方向进行搜索,故称之深度优先搜索。

现以下图中G为例说明深度优搜索过程。

假定v1是出发点,首先访问v1。

因v1有两个邻接点v2、v3均未被访问,选择v2作为新的出发点。

访问v2之后,再找v2的未访问过的邻接点。

同v2邻接的有v1、v4、v5,其中v1以被访问过,而v4、v5未被访问。

选择v4作为新的出发点。

重复上述搜索过程继续依次访问v8、v5。

访问v5之后,由于与v5相邻的顶点均以被访问,搜索退回到v8。

由于v8、v4、v2都没有未被访问的邻接点,所以搜索过程连续地从v8退回到v4,再退回到v2最后退回到v1这时选择v1的未被访问过的邻接点v3,继续往下搜索,依次访问v3、v6、v7,从而遍历了图中全部顶点。

在这个过程中得到的顶点的访问v1→v2→v4→v8→v5→v3→v6→v7这样的序列就称之为图的深度优先搜索遍历序列。

深度优先遍历算法typedef enum{FALSE,TRUE}Boolean;//FALSE为0,TRUE为1Boolean visited[MaxVertexNum]; //访问标志向量是全局量void DFSTraverse(ALGraph *G){ //深度优先遍历以邻接表表示的图G,而以邻接矩阵表示G时,算法完全与此相同int i;for(i=0;i<G->n;i++)visited[i]=FALSE; //标志向量初始化for(i=0;i<G->n;i++)if(!visited[i]) //vi未访问过DFS(G,i); //以vi为源点开始DFS搜索}//DFSTraverse3.3 连通图的广度优先搜索连通图广度优先搜索的基本思想是:从图中某个顶点v1出发,访问了v1之后依次访问v1的所有邻接点;并使“先被访问的顶点的领接点”先于“后被访问的顶点的领接点”被访问,直至图中所有已经被访问的顶点的领接点都被访问到。

它类似于树的按层次遍历,其特点是尽可能优先对横向搜索,故称之为广度优先搜索。

下面以图中G为例说明广度优先搜索的过程。

首先从起点v1出发,访问v1。

v1有两个未曾访问的邻接点v2和v3。

先访问v2,再访问v3。

然后再先后访问v2的未曾访问过的邻接点v4、v5及v3的未曾访问过的邻接点v6、v7。

最后访问v4的未曾访问过的邻接点v8。

至此图中所有顶点均以被访问到。

得到的顶点访问序列为:v1→v2→v3→v4→v5→v6→v7→v8相应的,这样的序列就称之为图的广度优先搜索遍历序列。

在广度优先搜索中,若对x的访问先于y,则对x邻接点的访问也先于对y的邻接点的访问。

因此,可采用队列来暂存那些刚访问过,但可能还有未访问过的邻接点的顶点。

连通图的广度优先搜索算法如下:void BFS(ALGraph*G,int k){// 以vk为源点对用邻接表表示的图G进行广度优先搜索int i;CirQueue Q; //须将队列定义中DataType改为intEdgeNode *p;InitQueue(&Q);//队列初始化//访问源点vkprintf("visit vertex:%e",G->adjlist[k].vertex);visited[k]=TRUE;EnQueue(&Q,k);//vk已访问,将其入队。

(实际上是将其序号入队)while(!QueueEmpty(&Q)){//队非空则执行i=DeQueue(&Q); //相当于vi出队p=G->adjlist[i].firstedge; //取vi的边表头指针while(p){//依次搜索vi的邻接点vj(令p->adjvex=j)if(!visited[p->adivex]){ //若vj未访问过printf("visitvertex:%c",C->adjlistlp->adjvex].vertex); //访问 vj visited[p->adjvex]=TRUE;EnQueue(&Q,p->adjvex);//访问过的vj入队}//endifp=p->next;//找vi的下一邻接点}//endwhile}//endwhile}//end of BFS4 最小生成树的两种经典算法构造最小生成树可以有很多算法。

其中多数算法利用了最小生成树的下列一种简称为MST的性质:假设N=(V,{E})是一个连通网,U是顶点集V的一个非空子集。

若(u,v)是一条具有最小权值(代价)的边,其中u属于U, v属于U的补集,则必存在一棵包含边(u,v)的最小生成树。

4.1 普里姆(Prim)算法求最小生成树的两种算法中,第一种被称为Prim算法。

它采用的方法是从图G中一条一条地选择边,并将他们加入到支撑树中(1)算法思想假设V是图中顶点的集合,E是图中边的集合,TE为最小生成树中的边的集合,则prim 算法通过以下步骤可以得到最小生成树:首先初始化:U={u 0},TE={M}此步骤设立一个只有结点u 0的结点集U和一个空的边集TE作为最小生成树的初始行态,在随后的算法执行中,这个行态会不断的发生变化,直到得到最小生成树为止。

然后在所有u∈U,v∈V-U的边(u,v)∈E中,找一条权最小的边(u 0,v 0),将此边加进集合TE中,并将此边的非U中顶点加入U中。

此步骤的功能是在边集E中找一条边,要求这条边满足以下条件:首先边的两个顶点要分别在顶点集合U和V-U中,其次边的权要最小。

找到这条边以后,把这条边放到边集TE中,并把这条边上不在U中的那个顶点加入到U中。

这一步骤在算法中应执行多次,每执行一次,集合TE和U都将发生变化,分别增加一条边和一个顶点,因此,TE和U是两个动态的集合。

如果U=V,则算法结束;否则重复步骤2。

可以把本步骤看成循环终止条件。

我们可以算出当U=V时,步骤2共执行了n-1次(设n为图中顶点的数目),TE中也增加了n-1条边,这n-1条边就是需要求出的最小生成树的边。

(2)Prim算法的伪代码描述PrimMST(G,T,r){//求图G的以r为根的MST,结果放在T=(U,TE)中InitCandidateSet(…);//初始化:设置初始的最短边候选集,并置T=({r},¢)for(k=0;k<n-1;k++){ //求n-1条树边(u,v)=SelectLiShtEdge(…);//选取最短边(u,v);T←T∪{(u,v)};//扩充TModifyCandidateSet(…); }}(3)算法的执行过程用PRIM算法得到最小生成树的过程注意:若候选轻边集中的轻边不止一条,可任选其中的一条扩充到T中。

相关文档
最新文档