很久以前已经接触过论的一些基本算法的,但是未曾亲自实现,只是了解一下原理,近期有空,开始对于图论算法整理。
在此kruskal算法中,用到并查集数据结构,并查集这个内容在博文[数据结构]并查集中有所介绍。
kruskal是一个贪心的算法,S为入选集,记录已经并入最小生成树中的边,Q为候选集,记录是待检查是否可并入最小生成树的边,m为总顶点数
1、从Q中选出一条边权值最小的边e
2、判断e加入S后是否使得S构成回路,若构成回路,则将e从Q剔除,以后不用再访问,再转向1,如果不构成回路,转向3
3、e加入S后,如果当前S中的边数目是总顶点数m-1,则已经找到最小生成树,退出循环,否则转向1继续寻找下一条合符条件的边
算法实现如下:
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 const int maxSize = 100; 5 typedef struct edge{//由kruskal算法可知,它是对边权值进行比较的, 6 //所以我们不适用邻接矩阵来表示图, 使用边的数据结构来表示图 7 int startPoint,endPoint; 8 int length; 9 }edge; 10 bool cmp(edge e1, edge e2){ 11 return e1.length < e2.length; 12 } 13 void makeSet(int* a, int n){ 14 for(int i = 0; i < n; ++i){ 15 a[i] = i; 16 } 17 } 18 int find(int* a, int x){ 19 if(x == a[x]){ 20 return x; 21 } 22 else{ 23 return a[x] = find(a,a[x]); 24 } 25 } 26 void unionSet(int* a,int x, int y){ 27 if(a[x] != a[y]){ 28 a[find(a,y)] = find(a,x); 29 } 30 } 31 int kruskal(edge* e, int n,int* a, int m){//m为顶点个数,n为边条数 32 sort(e,e+n,cmp); //sort是标准库algorithm中的函数,使得按权值上升 33 int i; 34 makeSet(a,m); 35 int sum = e[0].length;//初始化S,里面第一条边肯定是权值最小的边 36 unionSet(a,e[0].startPoint,e[0].endPoint);//把S中相互可达的顶点合到同一个组 37 int j = 1; 38 for(i = 1; j < m-1 && i < n; ++i){ 39 if( find(a,0)!=find(a,i) ){ 40 //当e[i]的两个顶点在S中是不可达的,表示两个顶点在S中的不同组里面, 41 //则加入e[i]不会有回路产生,只会把组合并 42 //(注意,同一个顶点可以在不同的边上) 43 unionSet(a,e[i].startPoint,e[i].endPoint); 44 sum += e[i].length; 45 ++j; 46 } 47 } 48 return sum; 49 } 50 int main(int argc, char**){ 51 const int infinite = 9999; 52 int map[maxSize][maxSize]={{0,5,infinite,infinite,7}, 53 {5,0,4,2,infinite}, 54 {infinite,4,0,6,8}, 55 {infinite,2,6,0,1}, 56 {7,infinite,8,1,0}}; 57 edge e[maxSize]; 58 int a[maxSize]; 59 int i,j; 60 int m = 5,n=0; 61 for(i = 0; i < m; ++i){ 62 for(j = i+1; j < m; ++j){ 63 if(map[i][j] < infinite){ 64 e[n].startPoint = i; 65 e[n].endPoint = j; 66 e[n++].length = map[i][j]; 67 } 68 } 69 } 70 cout<<kruskal(e,n,a,m); 71 }
本文基于知识共享署名-非商业性使用 3.0 许可协议进行许可。欢迎转载、演绎,但是必须保留本文的署名林羽飞扬,若需咨询,请给我发信