最小生成树Kruskal算法(邻接矩阵和邻接表)

  最小生成树,克鲁斯卡尔算法.

算法简述:

  将每个顶点看成一个图.

  在所有图中找权值最小的边.将这条边的两个图连成一个图,

  重复上一步.直到只剩一个图.

注:将abcdef每个顶点看成一个图.将最小权值的边的两个图连接.

连接最小权值为1的两个图,这时a-c,b,d,e,f.

连接最小权值为2的两个图,这时a-c,b,d-f,e.

连接最小权值为3的两个图,这时a-c,b-e,d-f.

连接最小权值为4的两个图,这时a-c-f-d,b-e.(c-f)

连接最小权值为5的两个图,这时a-c-b-e-f-d.(b-c)

结束.

根据上述操作,我们需要一个存储边信息的数组(Edge结构体),Edge包含了边的两个节点和权值.

1 typedef struct
2 {
3     int head;//边的始点下标
4     int tail;//边的终点下标
5     int power;//边的权值
6 } Edge;

还需要一个visited数组,用来标识图中的节点信息.

算法操作:

  初始化一棵树(用来保存最小生成树,直接输出也行.)

  将图中所有边复制到一个数组中,将数组排序(递增顺序)

  将小边的两个顶点连接.将两个图合并成一个图.

  重复上一步.

临街矩阵的代码实现

代码中,ijk做循环用,v1,v2做边的两个顶点信息的下标,vs1,vs2做标识v1和v2所属图

1-27行,初始化visited,edge,kruskal_tree等信息.

29-44行,生成一棵最小生成树.

35行,if是为了防止回路,vs1和vs2标识一个这两点是否属于一个图.

38行,for是为了将visited数组中vs2边成vs1,因为这时,v1和v2已经在一个图里了.

 1 void kruskal(Graph * graph, Graph * kruskal_tree)
 2 {
 3     int visited[graph->vertexs];
 4     Edge edge[graph->brim];
 5     int i, j, k;
 6     int v1, v2, vs1, vs2;
 7
 8     for ( i = 0; i < graph->vertexs; i++ )
 9         visited[i] = i;
10
11     k = 0;
12     for ( i = 0; i < graph->vertexs; i++ )
13     {
14         for ( j = i + 1; j < graph->vertexs; j++ )
15         {
16             if ( graph->arcs[i][j] != MAX_VALUE )
17             {
18                 edge[k].head = i;
19                 edge[k].tail = j;
20                 edge[k].power = graph->arcs[i][j];
21                 k++;
22             }
23         }
24     }
25
26     init_kruskal(graph, kruskal_tree);
27     my_sort(edge, graph->brim);
28
29     for ( i = 0; i < graph->brim; i++ )
30     {
31         v1 = edge[i].head;
32         v2 = edge[i].tail;
33         vs1 = visited[v1];
34         vs2 = visited[v2];
35         if ( vs1  != vs2 )
36         {
37             kruskal_tree->arcs[v1][v2] = graph->arcs[v1][v2];
38             for ( j = 0; j < graph->vertexs; j++ )
39             {
40                 if ( visited[j] == vs2 )
41                     visited[j] = vs1;
42             }
43         }
44     }
45 }

临街矩阵源码:http://www.cnblogs.com/ITgaozy/p/5200637.html

邻接表的代码实现

17行,if是为了将防止边的重复输入(在邻接矩阵中,点在矩阵中是对称的,所以我们只输入一个上三角中的数据就够了.但在邻接表中,我们如何判断一条边是否已经输入过了? 我的方法是将比当前节点下标大的输入,例如右a,b两个节点,a的节点小与b,我们在输入b的信息时,由于a的节点下标比b小,不输入a-b这条边,因为我们在输入a的信息时,a-b这条边已经输入过了.

 1 void kruskal(Graph * graph, Graph * kruskal_tree)
 2 {
 3     int visited[graph->vertexs];
 4     int i, j;
 5     Edge edge[graph->brim];
 6     int v1, v2, vs1, vs2;
 7     Arc_node * cur, * tmp;
 8
 9     for ( i = 0; i < graph->vertexs; i++ )
10         visited[i] = i;
11
12     for ( i = 0, j = 0; i < graph->vertexs; i++ )
13     {
14         cur = graph->adjlist[i].next;
15         while ( cur != NULL )
16         {
17             if ( cur->pos > i )
18             {
19                 edge[j].head = i;
20                 edge[j].tail = cur->pos;
21                 edge[j].power = cur->distance;
22                 j++;
23             }
24             cur = cur->next;
25         }
26     }
27
28     init_kruskal(graph, kruskal_tree);
29     my_sort(edge, graph->brim);
30
31     for ( i = 0; i < graph->brim; i += 1 )
32     {
33         v1 = edge[i].head;
34         v2 = edge[i].tail;
35         vs1 = visited[v1];
36         vs2 = visited[v2];
37         if ( vs1 != vs2 )
38         {
39             if ( kruskal_tree->adjlist[v1].next == NULL )
40             {
41                 kruskal_tree->adjlist[v1].next = make_node(v2, edge[i].power);
42             }
43             else
44             {
45                 tmp = kruskal_tree->adjlist[v1].next;
46                 while ( tmp->next != NULL )
47                     tmp = tmp->next;
48                 tmp->next = make_node(v2, edge[i].power);
49             }
50             for ( j = 0; j < graph->vertexs; j++ )
51             {
52                 if ( visited[j] == vs2 )
53                     visited[j] = vs1;
54             }
55         }
56     }
57 }

邻接表源码:http://www.cnblogs.com/ITgaozy/p/5200643.html

时间: 2024-10-13 02:39:45

最小生成树Kruskal算法(邻接矩阵和邻接表)的相关文章

最小生成树 Kruskal算法

Kruskal算法 1.概览 Kruskal算法是一种用来寻找最小生成树的算法,由Joseph Kruskal在1956年发表.用来解决同样问题的还有Prim算法和Boruvka算法等.三种算法都是贪婪算法的应用.和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效. 2.算法简单描述 1).记Graph中有v个顶点,e个边 2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边 3).将原图Graph中所有e个边按权值从小到大排序 4)

图的两种存储(邻接矩阵和邻接表)和两种遍历(DFS和BFS)

图的表示有很多,形式不固定,我暂时先记录我已经懂了的,能写的两种即大多数人应该都知道的邻接矩阵和邻接表. 邻接矩阵: 这里的邻接矩阵和离散数学说的有一点不同,至少有向图的邻接矩阵不同(离散书上的有向图的邻接矩阵求法到是有点像求任意两点的最短路径的Floyd算法) 以上都是(我现有知识认为的)废话: 重点 : G : 表示图: Nv:表示图的点数: Ne:表示图的边数: 邻接矩阵 即是一个 Nv * Nv 的矩阵,矩阵是用来储存  权值的(如果是带权图且有边的话),如果是无权图的的话,如果两顶点有

图的存储结构:邻接矩阵(邻接表)&amp;链式前向星

[概念]疏松图&稠密图: 疏松图指,点连接的边不多的图,反之(点连接的边多)则为稠密图. Tips:邻接矩阵与邻接表相比,疏松图多用邻接表,稠密图多用邻接矩阵. 邻接矩阵: 开一个二维数组graph[ ][ ]来记录图中点a与点b之间是否连通,初始化为0(或者-1之类的看情况):如果图中有可忽略的重边(如 只需重边中的最小边或最大边),则保存需要的那条边的边权,但如果有无法忽略的重边,就一定不要用邻接矩阵. int graph[MAXN][MAXN]; void graphInit() { me

SOJ4339 Driving Range 最小生成树 kruskal算法

典型的最小生成树 然后求最大的一条边 附上链接 http://cstest.scu.edu.cn/soj/problem.action?id=4339 需要注意的是有可能有 "IMPOSSIBLE" 的情况 这里用一个flag标记 记录所并的节点 只有flag = n时才能成功 负责就 "IMPOSSIBLE" 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring&g

最小生成树 kruskal算法简介

生成树--在一个图中的一个联通子图  使得所有的节点都被(访问) 最小生成树 (MST) 即联通子图的总代价(路程)最小 已知的一个图 有n个点 m条边 kruskal的算法如下 先对边从小到大排序 从最小的边起,不停的合并这条边的两个节点到一个集合,如果这条边的两个节点已经在一个集合里,则无视,否则形成回路(显然错误)直到所有的节点并到一个集合里 这里需要用到并查集来合并节点 1 int cmp(const int i,const int j) { 2 return w[i] < w[j];

PAT1013. Battle Over Cities(邻接矩阵、邻接表分别dfs)

//采用不同的图存储结构结构邻接矩阵.邻接表分别dfs,我想我是寂寞了吧,应该试试并查集,看见可以用并查集的就用dfs,bfs代替......怕了并查集了 //邻接矩阵dfs #include<cstdio>#include<algorithm>using namespace std;const int maxn=1001;int g[maxn][maxn];int n,tmp;bool vis[maxn];void dfs(int v){ vis[v]=true; for(int

无向图的表示:邻接矩阵和邻接表

这里将一个无向图用邻接表和邻接矩阵表示. 输入:顶底个数n,图中的各个边(用两个顶点表示). 输出:这个无线图的邻接矩阵和邻接表,其中邻接表中的链接按元素大小升序排列. 先给出一个例子说明.假设有无向图如下,则其邻接矩阵和邻接表如提示框中所示(其实就是下面程序的输出). 下面是程序的代码: #include <stdio.h> #include <stdlib.h> //图的表示,输入节点个数和边,构造图的邻接矩阵和邻接表 //邻接表中的链表节点 struct vNode{ int

图的邻接矩阵与邻接表

一.如何创建邻接表和邻接矩阵? 如图,根据上图建立一个无向图的邻接矩阵和邻接表~ 输入的数据,第一行为两个整数n,e(0<n<=1000,0<e<=5000),表示有n个点和e条边,接下来的e行,每行包含2个整数,表示每条边所连接的两个点. 然后输出图.(无硬性要求) 输入数据: 5 81 01 21 32 32 43 43 04 0 输出数据(示例): 0->1->3->4->NULL1->0->2->3->NULL2->1-

无向图最小生成树Kruskal算法

问题 最小生成树的Kruskal算法 描述:有A.B.C.D四个点,每两个点之间的距离(无方向)是(第一个数字是两点之间距离,后面两个字母代表两个点):(1,'A','B'),(5,'A','C'),(3,'A','D'),(4,'B','C'),(2,'B','D'),(1,'C','D') 生成边长和最小的树,也就是找出一种连接方法,将各点连接起来,并且各点之间的距离和最小. 思路说明: Kruskal算法是经典的无向图最小生成树解决方法.此处列举两种python的实现方法.这两种方法均参考

最小生成树Kruskal算法的提出者Joseph Bernard Kruskal,Jr.

熟悉算法中的最小生成树的朋友都晓得有一个Kruskal算法,这个算法就是由题目中那个名字很长的人提出的.因为他功绩卓越,尊称他为Kruskal. Kruskal生于1928年1月29日,卒于2010年9月19日,美国人,维基里的词条中包含的头衔是:数学家.统计学家.计算机科学家.心理测量学专家. kruskal分别就读过芝加哥大学和普林斯顿大学,1954年获得博士学位. 下面链接中是一篇几年他的文章,从中可以了解他的更多成就.顺便说一句,他的父母和兄弟也都很牛. http://pan.baidu