1、Kruskal
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
public class Kruskal {
/**
* 求最小树的Kruskal算法
* 算法思想:克鲁斯卡尔算法从另一个途径求网中的最小生成树。假设联通网N=(V,{E}),则令最小
* 生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{}),途中每个顶点自称一个连通分量。
* 在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边
* 而选择下一条最小的边。以此类推,直至T中所有的顶点都在同一连通分量上为止。
* 1 2 3 4 5 6 //初始状态
* (1 3) 2 4 5 6 //顶点13连通,(1 3)是不是连通分量
* (1 3) (2 5) 4 6 //25连通
* (1 2 3 5) 4 6 //35连通,则1 2 3 5整体连通,成为一个连通分量
* (1 2 3 4 5 6)结束//两顶点若存在同一个连通分量上,则表示存在环,去除此边
* @param V 图中的节点集合
* @param E 图中边的集合
*/
public static void KRUSKAL(int [] V,Edge [] E){
Arrays.sort(E);//将边按照权重w升序排序
ArrayList<HashSet<Integer>> sets=new ArrayList<HashSet<Integer>>();
for(int i=0;i<V.length;i++){
HashSet<Integer> set=new HashSet<Integer>();
set.add(V[i]);
sets.add(set);
}
for(int i=0;i<E.length;i++){
int start=E[i].i,end=E[i].j;
int counti=-1,countj=-2;
for(int j=0;j<sets.size();j++){
HashSet<Integer> set=sets.get(j);
if(set.contains(start)){
counti=j;
}
if(set.contains(end)){
countj=j;
}
}
if(counti<0||countj<0) System.err.println("没有在子树中找到节点,错误");
if(counti!=countj){
System.out.println("输出start="+start+"||end="+end+"||w="+E[i].w);
HashSet<Integer> setj=sets.get(countj);
sets.remove(countj);
HashSet<Integer> seti=sets.get(counti);
sets.remove(counti);
seti.addAll(setj);
sets.add(seti);
}else{
System.out.println("他们在一棵子树中,不能输出start="+start+"||end="+end+"||w="+E[i].w);
}
}
}
public static void main(String [] args){
int [] V={1,2,3,4,5,6};
Edge [] E=new Edge[10];
E[0]=new Edge(1,2,6);
E[1]=new Edge(1,3,1);
E[2]=new Edge(1,4,5);
E[3]=new Edge(2,3,5);
E[4]=new Edge(2,5,3);
E[5]=new Edge(3,4,5);
E[6]=new Edge(3,5,6);
E[7]=new Edge(3,6,4);
E[8]=new Edge(4,6,2);
E[9]=new Edge(5,6,6);
Kruskal.KRUSKAL(V, E);
}
}
class Edge implements Comparable<Object> {
public int i, j, w;
public Edge(int i, int j, int w) {
this.i = i;
this.j = j;
this.w = w;
}
@Override
public int compareTo(Object o) {
Edge to = (Edge) o;
if (this.w > to.w)
return 1;
else if (this.w == to.w)
return 0;
else
return -1;
}
@Override
public String toString() {
return "start=" + i + "||end=" + j + "||w=" + w;
}
}
2、Prim
import java.util.*;
public class Prim {
static int MAX = Integer.MAX_VALUE;
public static void main(String[] args) {
int[][] map = new int[][] {
{ 0, 10, MAX, MAX, MAX, 11, MAX, MAX, MAX },
{ 10, 0, 18, MAX, MAX, MAX, 16, MAX, 12 },
{ MAX, MAX, 0, 22, MAX, MAX, MAX, MAX, 8 },
{ MAX, MAX, 22, 0, 20, MAX, MAX, 16, 21 },
{ MAX, MAX, MAX, 20, 0, 26, MAX, 7, MAX },
{ 11, MAX, MAX, MAX, 26, 0, 17, MAX, MAX },
{ MAX, 16, MAX, MAX, MAX, 17, 0, 19, MAX },
{ MAX, MAX, MAX, 16, 7, MAX, 19, 0, MAX },
{ MAX, 12, 8, 21, MAX, MAX, MAX, MAX, 0 } };
prim(map, map.length);
}
public static void prim(int[][] graph, int n){
char[] c = new char[]{'A','B','C','D','E','F','G','E','F'};
int[] lowcost = new int[n]; //到新集合的最小权
int[] mid= new int[n];//存取前驱结点
List<Character> list=new ArrayList<Character>();//用来存储加入结点的顺序
int i, j, min, minid , sum = 0;
//初始化辅助数组
for(i=1;i<n;i++)
{
lowcost[i]=graph[0][i]; //初始是以0为起点到各个节点的权重
mid[i]=0; //记录每个节点的起点为0
}
list.add(c[0]);
//一共需要加入n-1个点
for(i=1;i<n;i++)
{
min=MAX;
minid=0;
//每次找到距离集合最近的点
for(j=1;j<n;j++)
{
if(lowcost[j]!=0&&lowcost[j]<min)
{
min=lowcost[j];
minid=j;
}
}
if(minid==0) return;
list.add(c[minid]);
lowcost[minid]=0;
sum+=min;
System.out.println(c[mid[minid]] + "到" + c[minid] + " 权值:" + min);
//加入该点后,更新其它点到集合的距离
for(j=1;j<n;j++)
{
if(lowcost[j]!=0&&lowcost[j]>graph[minid][j])
{
lowcost[j]=graph[minid][j];
mid[j]=minid;
}
}
}
System.out.println("sum:" + sum);
}
}