最小生成树是图论中的经典问题,我们常用的算法基于dikstra算法改进的prim算法,还有一种就是利用并查集实现的kruska算法了。
下面我们来看看代码实现:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* 最小生成树
* 1.Prim算法
* 2.Kruska算法
* @author Administrator
*
*/
public class MST {
private static int[][] costs = {
{0,1,Integer.MAX_VALUE,9,Integer.MAX_VALUE,Integer.MAX_VALUE,2},
{1,0,8,1,3,Integer.MAX_VALUE,Integer.MAX_VALUE },
{Integer.MAX_VALUE,8,0,Integer.MAX_VALUE,6,Integer.MAX_VALUE,Integer.MAX_VALUE },
{9,1,Integer.MAX_VALUE,0,5,5,3},
{Integer.MAX_VALUE,3,6,5,0,8,Integer.MAX_VALUE},
{Integer.MAX_VALUE,Integer.MAX_VALUE,Integer.MAX_VALUE,5,8,0,10} ,
{2,Integer.MAX_VALUE,Integer.MAX_VALUE,3,Integer.MAX_VALUE,10,0} };
public static void main(String[] args) {
long x = System.currentTimeMillis(),y;
prim();
y = System.currentTimeMillis();
System.out.println("用时:"+(y-x)+"ms");
x = System.currentTimeMillis();
kruska();
y = System.currentTimeMillis();
System.out.println("用时:"+(y-x)+"ms");
}
/**
* prim算法求最小生成树,算法是基于dikstra算法改进的
* @param num
* @param isUsed
* @param pre
* @param costs
* @param d
*/
private static void prim() {
int shortestPath = 0;
int num = 7;
int[] d = new int[num];
//标示source到其它节点是否已经求出最短路径
boolean[] isUsed = new boolean[num];
//路径还原时用,存放路径中上一个节点下标
int[] pre = new int[num];
//初始化
for (int i = 0; i < num; i++) {
isUsed[i] = false;
}
for (int i = 0; i < num; i++) {
pre[i] = -1;
}
fill(num,d);
while (true) {
int i = getMinIndex(isUsed, num, d);
if (i == -1) {
break;
}
//i号节点是未加入生成树的节点中离树最近的节点,先将其加入树中
isUsed[i] = true;
shortestPath+=d[i];
for (int j = 0; j < num; j++) {
if (!isUsed[j] && (d[j] > costs[i][j])) {
d[j] = costs[i][j];
//存放上一节点下标
pre[j] = i;
}
}
}
System.out.println("prim算法最小生成树路径信息:");
for(int i=1;i<num;i++){
System.out.println("结点"+i+"---"+"结点"+pre[i]);
}
System.out.println("prim算法最小生成树路径总和:"+shortestPath);
}
/**
* 在未加入最小生成树的所有节点中选出离生成树最近的节点
* @param isShort
* @param num
* @param d
* @return
*/
private static int getMinIndex(boolean[] isUsed, int num, int[] d) {
int i = -1;
for (int u = 0; u < num; u++) {
if (!isUsed[u] && (i == -1 || d[u] < d[i]))
i = u;
}
return i;
}
/**
* 距离初始化
* @param s
* @param num
* @param costs
* @param d
*/
private static void fill(int num,int[] d) {
for (int i = 0; i < num; i++) {
d[i] = Integer.MAX_VALUE;
}
//从0号节点开始
d[0] = 0;
}
/**
* Kruska算法
*/
private static void kruska(){
int num = 7;
int shortestPath = 0;
//并查集
BingChaSet bingChaSet = new BingChaSet(num);
List<Route> list = new ArrayList();
//向集合中添加路径信息
for(int i=0;i<num-1;i++){
for(int j=i+1;j<num;j++){
if(costs[i][j]!=Integer.MAX_VALUE){
list.add(new Route(i,j,costs[i][j]));
}
}
}
//根据权重排序
if(list.size()>0){
Collections.sort(list, new MyCompartor());
}
num = list.size();
System.out.println("kruska算法最小生成树路径信息:");
for(int i=0;i<num;i++){
Route r = list.get(i);
if(!bingChaSet.isSame(r.first,r.second )){
//如果两个节点不在同一组则选取为生成树中的路径
bingChaSet.merge(r.first, r.second);
shortestPath+=r.priority;
System.out.println("结点"+r.first+"---"+"结点"+r.second);
}
}
System.out.println("kruska算法最小生成树路径总和:"+shortestPath);
}
/**
* 路径信息封装类
* @author Administrator
*
*/
static class Route{
int first,second,priority;
public Route(int first,int second,int priority){
this.first = first;
this.second = second;
this.priority = priority;
}
}
/**
* 比较器
* @author Administrator
*
*/
static class MyCompartor implements Comparator<Route>{
@Override
public int compare(Route o1, Route o2) {
if(o1.priority>o2.priority)
return 1;
else if(o1.priority<o2.priority)
return -1;
return 0;
}
}
/**
* 并查集
* @author Administrator
*
*/
static class BingChaSet{
private int par[],height[];
public BingChaSet(int num) {
par = new int[num];
height = new int[num];
for(int i=0;i<num;i++){
par[i] = i;
height[i] = 0;
}
}
//得到父亲节点的index
private int getParentIndex(int i){
if(par[i]==i)
return i;
else
return par[i] = getParentIndex(par[i]);
}
//判断两节点是否属于同一组
public boolean isSame(int i,int j){
return getParentIndex(i)==getParentIndex(j);
}
//合并两节点所在的组
public void merge(int i,int j){
int x = getParentIndex(i);
int y = getParentIndex(j);
if(x==y)
return;
if(height[x]>height[y]){
par[y] = x;
}else{
par[x] = y;
if(height[x]==height[y]){
height[y]++;
}
}
}
}
}