首先来介绍一下:图的最小树的概念
树是一种没有回路和环路的图
并且我们知道:只要我们对树结构进行遍历,就能够走遍树结构中的左右节点(比如二叉树的4种遍历方式)
并且,通过一张图所能够得到树结构的方案是有很多种的
那么在无向带权图中,我们为图中的每一条边都分配了权值
如果我们在删除一些边,去掉图中回路和环路之后保留下来的树结构中,所有节点之间边权的加和是所有方案中最小的
我们称这种树结构为无向图的最小生成树结构
最小生成树中保留了原有图中所有的节点,这些节点保存在同一个树结构当中,并且这个数的所有边权之和如其他树结构相比,取值最小
在数据结构所涉及的相关算法中,有两种算法可以用来计算无向图的最小生成树:普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法
普利姆算法
先画个示例图
步骤
步骤1:在所有的边中选择一个边权最小的边(如果具有相同最小权值的边有好几个,那么就随便选一个),使用这个边将两个节点连接起来,也就是将这个边加入生成树结构中
步骤2:将上述步骤中用到的点,存放在一个数组中,这个集合称之为“用过的点的集合”(一会儿我们要用这个集合来判断新选择的边是不是会构成回路)
步骤3:查找和所有已经用过的点相关的边,在这些边中挑出一个权值最小的边,加入生成树结构中,
但是在挑选的过程中我们需要保证:被选择的点,不能够出现在“用过的点的集合”中,因为如果出现这种情况,说明选择的边将使得图中出现回路,那就不是树结构了
步骤4:将这个距离最近的点,同样加入“用过的点的集合”
步骤5:重复步骤3-4,直到边的个数为节点的数量减一时候,说明所有的节点都已经加入最小生成树结构中了,程序终止
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
A | 0 | 6 | 1 | 5 | ∞ | ∞ |
B | 6 | 0 | 5 | ∞ | 3 | ∞ |
C | 1 | 5 | 0 | 5 | 6 | 4 |
D | 5 | ∞ | 5 | 0 | ∞ | 2 |
E | ∞ | 3 | 6 | ∞ | 0 | 6 |
F | ∞ | ∞ | 4 | 2 | 6 | 0 |
实现的代码
图的临界矩阵表示
/**
* 图的临界矩阵表示
* @author 80769
*
*/
public class MGraph {
int size;//图中的节点个数
char[] data;//存放的节点
int[][] weight;//存放的边
public MGraph(int size) {
this.size=size;
this.data=new char[size];
weight=new int[size][size];
}
}
实现最小生成树
/**
* 创建图的邻接矩阵
*
* @author xhh
*
*/
public class MinTree {
public void createGraph(MGraph graph, int size, char data[], int[][] weight) {
for (int i = 0; i < size; i++) {
graph.data[i] = data[i];
for (int j = 0; j < size; j++) {
graph.weight[i][j] = weight[i][j];
}
}
}
/**
* 普利姆算法的实现
*
* @param graph 图的临界表
* @param node 起始顶点
*/
public int prim(MGraph graph, int node) {
int sum=0;//权值总和
int[] visited = new int[graph.size];// 创建一个数组,存放是否被访问过的节点
for (int i = 0; i < graph.size; i++) { // 初始化数组
visited[i] = 0;
}
visited[node]=1;
int h1=-1;//边的弧尾
int h2=-1;//边的头
int minweight=Integer.MAX_VALUE; //最小权重
for(int i=1;i<graph.size;i++) { //size个顶点,最小生成树中有size-1条边
for(int j=0;j<graph.size;j++) { //j顶点表示被访问过的顶点
for(int k=0;k<graph.size;k++) { //k顶点表示被访问过的顶点
if(visited[j]==1 && visited[k]==0 && graph.weight[j][k]<minweight && graph.weight[j][k]!=0) {
//寻找已访问的顶点与未访问的定点间的权值最小的边
minweight=graph.weight[j][k];
h1=j;
h2=k;
}
}
}
System.out.println("边<"+graph.data[h1]+","+graph.data[h2]+"> 权值:"+minweight);
visited[h2]=1;
sum+=minweight;
minweight=Integer.MAX_VALUE;
}
return sum;
}
public static void main(String[] args) {
int maxValue=Integer.MAX_VALUE;
char[] data=new char[] {'A','B','C','D','E','F'};
int size=data.length;
int[][] weight=new int[][] {
{0,6,1,5,maxValue,maxValue},
{6,0,5,maxValue,3,maxValue},
{1,5,0,5,6,4},
{5,maxValue,5,0,maxValue,2},
{maxValue,3,6,maxValue,0,6},
{maxValue,maxValue,4,2,6,0}
};
MGraph mGraph = new MGraph(size);
MinTree minTree=new MinTree();
minTree.createGraph(mGraph, size, data, weight);
int sum = minTree.prim(mGraph, 0);
System.out.println("权值总和:"+sum);
}
}
运行结果