最小生成树算法Prim、Kruskal
2015-09-23 21:33
399 查看
在看本文之前最好先看看算法分析之最小生成树
在介绍两种算法之前,我需要先介绍一个推论首先介绍一个概念,连通分量:其实就是一棵树(某些树也可能是一个节点)
推论:对于无向连通图G=(V,E)。设A是G的某棵最小生成树的子集,并设C=(Vc,Ec)为森林Ga=(V,A)的一个连通分量,如果边(u,v)是连接C和Ga中某个其他连通分量的一条轻量级边,则(u,v)对于A来说是安全的。
Kruskal算法
在所有的连接两颗树的边里找到权重最小的边(u,v),设C1,C2分别为u,v所连接的两个连通分量由于(u,v)一定是连接两个连通分量C1,C2的轻量级边,由推论可知(u,v)是安全的
算法伪代码:
A=null
对G中的边E按权重w对每条边安卓小到大的顺序进行排序
for each (u,v)∈G.E{
如果u,v不属于同一颗树{
A=A∪{(u,v)}
将u,v所在的树合并成一棵树
}
}
具体过程可以用下图来说明
算法模板:
Prim算法
算法的每一步都寻找一条横跨切割(A,V-A)的轻量级边作为A的安全边
设v.key为v到A中每个结点的边中最小边的权重
伪代码:
A=null
Q=G.V
任意确定一个点作为root加入到A中
while(Q!=null){
从Q找出结点u,u.key是Q中的所有结点中最小的
将u加入到A并从Q中删除
更新与u相连的结点的v.key
}
用下面的一系列图来说明:
prim模板如下:
在介绍两种算法之前,我需要先介绍一个推论首先介绍一个概念,连通分量:其实就是一棵树(某些树也可能是一个节点)
推论:对于无向连通图G=(V,E)。设A是G的某棵最小生成树的子集,并设C=(Vc,Ec)为森林Ga=(V,A)的一个连通分量,如果边(u,v)是连接C和Ga中某个其他连通分量的一条轻量级边,则(u,v)对于A来说是安全的。
Kruskal算法
在所有的连接两颗树的边里找到权重最小的边(u,v),设C1,C2分别为u,v所连接的两个连通分量由于(u,v)一定是连接两个连通分量C1,C2的轻量级边,由推论可知(u,v)是安全的
算法伪代码:
A=null
对G中的边E按权重w对每条边安卓小到大的顺序进行排序
for each (u,v)∈G.E{
如果u,v不属于同一颗树{
A=A∪{(u,v)}
将u,v所在的树合并成一棵树
}
}
具体过程可以用下图来说明
算法模板:
public class Mian { public static void main(String[] args) { /** * 对fatherV初始化 **/ for (int i = 0; i < fatherV.length; i++) { fatherV[i]=i; } /** * 给e赋值 **/ //TODO /** * 给V赋值 **/ //TODO kruskal(); } static int V;//结点的个数 static int[] fatherV=new int[100];//farher[i]=j表示结点i的父节点为j static Edge[] e=new Edge[100]; static class Edge{ int u,v,w; Edge(int u,int v,int w){ this.u=u; this.v=v; this.w=w; } } /** * 寻找结点x所在树的根节点 **/ static int findRoot(int x) { return (x==fatherV[x]) ? x : findRoot(fatherV[x]); } /** * 判断结点u,v是否属于同一棵树,如果不属于同一棵树就将u,v所在的树合并为一棵树 **/ static boolean judgeIsSameTree(int u,int v) { int root1=findRoot(u); int root2=findRoot(v); if(root1==root2)//u,v在同一棵树中 { return true; } else { fatherV[u]=v;//将u,v所在的两颗树合并 } return false; } static void kruskal() { boolean flag=false; int numEgdeInTree=0; quickSort(0, e.length); for(int i=0;i<e.length;i++) { if(!judgeIsSameTree(e[i].u, e[i].v)) { numEgdeInTree++; if(numEgdeInTree==V-1)//找到了一棵最小生成树 { flag=true; break; } } } if(flag) { //TODO } else { System.out.println("can not find a minimal spanning tree"); } } /** * 快排对e按w进行升序排序,这里排序可以随意选择方法,也可以用语言给定好的排序函数 **/ static void quickSort(int l,int r){ if(l>=r){ return; } int q=partition(l, r); quickSort(l, q-1); quickSort(q+1, r); } static int partition(int l,int r){ int i=l;int j=r;int x=e[i].w; while(i<j){ while(i<j && e[j].w>=x) j--; if(i<j){ e[i].w=e[j].w; i++; }else { break; } while(i<j && e[i].w<=x) i++; if(i<j){ e[j].w=e[i].w; j--; }else { break; } } //显然退出时i=j e[i].w=x; return i; } }
Prim算法
算法的每一步都寻找一条横跨切割(A,V-A)的轻量级边作为A的安全边
设v.key为v到A中每个结点的边中最小边的权重
伪代码:
A=null
Q=G.V
任意确定一个点作为root加入到A中
while(Q!=null){
从Q找出结点u,u.key是Q中的所有结点中最小的
将u加入到A并从Q中删除
更新与u相连的结点的v.key
}
用下面的一系列图来说明:
prim模板如下:
public class Main { public static void main(String[] args) { prim(); } static int[] low=new int[100];//low[i]=d表示结点i到A中的结点的最小边的权值为d static int used[]=new int[100];//used[i]=1,0分别表示i结点在集合A中和i结点不在集合A中 static int n;//图中结点的数目 static int[][] w=new int[100][100];//w[i][j]结点i到j的边的权值 static void prim(){ //初始化所有结点的low值全部设为无限大 for(int i=0;i<low.length;i++) { low[i]=2147483647; } //以结点0为初始结点,标记该结点 int pos=0;used[pos]=1; for(int i=1;i<n;i++) { low[i]=w[pos][i]; } for(int i=1;i<n;i++) { /** * 找出集合A到A以外的结点的边的权值最小的结点 **/ int min_low=1000000; for(int j=1;j<n;j++) { if(used[j]==0 && low[j]<min_low) { min_low=low[j]; pos=j; } } /** * 将找到的结点加入到集合A,并更新与该结点相连的结点的low值 **/ used[pos]=1; for(int j=1;j<n;j++) { if(used[j]==0 && w[pos][j]<low[j]) { low[j]=w[pos][j]; //TODO,结点j的父节点为pos } } } } }
相关文章推荐
- java面试题集锦
- [HW] OJ记录20题之三
- 读取网络中的数据并写入数据库
- MongoDB数据库设计中6条重要的经验法则,part 1(每日一译:2014-07-23)
- Qt 出现“undefined reference to `vtable for”原因总结
- 2022海选女主角
- 杭电acm--2046
- 黑马程序员----C 语言学习笔记之机器数、真值、原码、反码、补码
- YARN基本组成结构
- matlab函数isfield、cell2mat、vertcat
- JavaScript日期时间格式化函数
- tnsnames linux找的位置顺序
- SDWebImage
- [css]兼容性
- UVALIVE 3346 Perfect Domination on Trees 树形DP
- HDU1026 Ignatius and the Princess I(java)
- 中断及中断处理过程
- Android导航栏--ActionBar
- 爬虫学习-使用CrawlSpider
- java12 File类