Prim算法:
算法思路:
1.定义一个临时的一维数组,用于存放可用的连接边,数组下标为顶点序号,值为权值
2.任选一个点作为起点,以起点的所有权值对数组进行初始化
3.找出数组中最小权值的边,即为最小生成树中的一条有效边
4.将找到的最小边在数组中赋值为0,代表已经使用过。并将数组与找到顶点的所有边进行比较,若顶点的边的权值比当前数组存放的可用边的权值小,则进行覆盖
5.重复循环2,3,4的操作直至遍历完所有顶点
/**
* prim算法实现最小生成树
* @param arr 图的邻接矩阵
* @param size 图的节点个数
* @param nodes 存放节点名称的数组
*/
private static void Prim(int[][] arr,int size,char[] nodes){
//创建一个一维数组,存放用于比较最小权值的顶点权值,值为0表示该点已经比较过
int[] lowcost = new int[size];
//初始化为原数组第一个顶点的权值
lowcost = Arrays.copyOfRange(arr[0],0,size);
//初始化权值之和为0
int sum = 0;
//循环比较
for (int i = 0; i < size-1; i++) {
int min = -1;
//找到最小权值节点
for (int j = 0; j < size; j++) {
if(lowcost[j] != 0 && lowcost[j] < Integer.MAX_VALUE){
if(min == -1 || lowcost[j] < lowcost[min] ){
min = j;
}
}
}
//如果所有节点都比较过(值为0),则直接退出
if(min == -1) break;
//输出加入的新节点
System.out.println("加入新节点:"+nodes[min]+" 权值为:"+lowcost[min]);
//增加权值之和
sum += lowcost[min];
// 将当前节点的值修改成0
lowcost[min] = 0;
//将存放最小权值的数组与下一个节点的所有连接点对比,找出最小权值
for (int j = 0; j < size; j++) {
if(arr[min][j] < lowcost[j] ){
lowcost[j] = arr[min][j];
}
}
}
System.out.println("权值之和:"+sum);
}
Kruskal算法:
算法思路:
1.现将所有边进行权值的从小到大排序
2.定义一个一维数组代表连接过的边,数组的下标为边的起点,值为边的终点
3.按照排好序的集合用边对顶点进行依次连接,连接的边则存放到一维数组中
4.用一维数组判断是否对已经连接的边能构成回路,有回路则无效,没回路则是一条有效边
5.重复3,4直至遍历完所有的边为止,即找到最小生成树
/**
* Kruskal算法
* @param array 各边权重数组
* @param size 节点个数
* @param chars 存放节点名称的数组
*/
private static void Kruskal(int[][] array,int size,char[] chars){
//创建一维数组,数组下标为连线的起点,下标对应的值为连线的终点
int[] parent = new int[size];
for (int i = 0; i < size; i++) {
parent[i] = 0;
}
//定义初始权值之和为0
int sum = 0;
for (int i = 0; i < array.length; i++) {
//找到起始节点和终点在连接集和中的最后一个节点
int start = find(parent,array[i][0]);
int end = find(parent,array[i][1]);
//若通过起点和终点找到的最终连接点不是同一个点,则不是回环
if(start != end){
parent[start] = end;
System.out.println("起点:"+chars[array[i][0]]+" 终点:"+chars[array[i][1]]+" 权重:"+array[i][2]);
sum += array[i][2];
}
}
System.out.println("权值之和:"+sum);
}
//获取集和的最后一个节点
private static int find(int[] parent, int index) {
while(parent[index] > 0){
index = parent[index];
}
return index;
}
分别用两种算法实现上图最小生成树代码:
public static void main(String[] args) {
//初始化权值矩阵
int[][] arr = new int[][]{
{0,2,Integer.MAX_VALUE,5,Integer.MAX_VALUE,8,Integer.MAX_VALUE},
{2,0,7,7,2,Integer.MAX_VALUE,Integer.MAX_VALUE},
{Integer.MAX_VALUE,7,0,Integer.MAX_VALUE,3,Integer.MAX_VALUE,Integer.MAX_VALUE},
{5,7,Integer.MAX_VALUE,0,6,7,3},
{Integer.MAX_VALUE,2,3,6,0,Integer.MAX_VALUE,4},
{8,Integer.MAX_VALUE,Integer.MAX_VALUE,7,Integer.MAX_VALUE,0,4},
{Integer.MAX_VALUE,Integer.MAX_VALUE,Integer.MAX_VALUE,3,4,4,0}
};
char[] chars = new char[]{'A','B','C','D','E','F','G'};
System.out.println("Prim算法:");
Prim(arr,chars.length,chars);
//换行
System.out.println();
int[][] array = new int[][]{
{0,1,2},
{1,4,2},
{2,4,3},
{3,6,3},
{4,6,4},
{5,6,4},
{0,3,5},
{3,4,6},
{1,2,7},
{1,3,7},
{3,5,7},
{0,5,8},
};
System.out.println("Kruskal算法:");
Kruskal(array,chars.length,chars);
}