package com.ldp.algorithm.demo04Prim;
import org.junit.Test;
import java.util.Arrays;
/**
* @create 06/05 6:24
* @description <p>
* 普里母算法
* 案例修路问题,求修路的路径最短
* </p>
*/
public class Test01 {
int dv = 10000; // 默认值10000表示不能连通(不修路)
/**
* 测试普里母算法
*/
@Test
public void test01() {
// 定义节点
char[] nodeArray = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
// 使用二维数组表示各节点是否连通
int[][] weight = {
{dv, 5, 7, dv, dv, dv, 2},
{5, dv, dv, 9, dv, dv, 3},
{7, dv, dv, dv, 8, dv, dv},
{dv, 9, dv, dv, dv, 4, dv},
{dv, dv, 8, dv, dv, 5, 4},
{dv, dv, dv, 4, 5, dv, 6},
{2, 3, dv, dv, 4, 6, dv}};
// 创建图对象
MyGraph myGraph = new MyGraph(nodeArray.length);
// 创建一个minTree对象
MinTree minTree = new MinTree();
minTree.createGraph(myGraph, nodeArray, weight);
// 数据显示
minTree.showGraph(myGraph);
// 修路方案
minTree.prim(myGraph);
}
}
/**
* 创建最小生成树-->修路图
*/
class MinTree {
/**
* 创建图的邻接矩阵
*
* @param graph
* @param nodeArray
* @param weight
*/
public void createGraph(MyGraph graph, char[] nodeArray, int[][] weight) {
int num = nodeArray.length;
for (int i = 0; i < num; i++) {
graph.nodeArray[i] = nodeArray[i];
for (int j = 0; j < num; j++) {
graph.weight[i][j] = weight[i][j];
}
}
}
/**
* 显示图(矩阵),即遍历二维数组
*
* @param myGraph
*/
public void showGraph(MyGraph myGraph) {
int[][] weight = myGraph.weight;
for (int[] ints : weight) {
System.out.println(Arrays.toString(ints));
}
}
/**
* 普里母算法
*
* @param myGraph
*/
public void prim(MyGraph myGraph) {
int dv = 10000; // 默认值10000表示不能连通(不修路)
// 存放已经被访问过的点,默认为0表示没有被访问
int[] visited = new int[myGraph.num];
// 默认第一个节点已经被访问
visited[0] = 1;
// h1 和 h2 记录两个节点的下标,给个默认值-1;
int h1 = -1;
int h2 = -1;
// 表示默认节点h1到h2之间要修的路很长,即不通
int minWeight = dv;
// 遍历所有需要访问的节点
// 为什么从1开始,因为默认第一个点是被访问了的 visited[0] = 1;
for (int v = 1; v < myGraph.num; v++) {
// 在所有已访问的节点 和 所有没有访问的节点中找到一条最短的路径
for (int i = 0; i < myGraph.num; i++) { // 表示已访问的节点下标
// 如果是没有被访问的几点就跳过
if (visited[i] != 1) {
continue;
}
for (int j = 0; j < myGraph.num; j++) {// 没有被访问的节点下标
// 如果是已访问的几点就跳过
if (visited[j] == 1) {
continue;
}
// 判定是否为最短
if (myGraph.weight[i][j] < minWeight) {
minWeight = myGraph.weight[i][j];
h1 = i;
h2 = j;
}
}
}
// 找到了一条最小边
System.out.println("需要修的路:" + myGraph.nodeArray[h1] + "->" + myGraph.nodeArray[h2] + ",长度为:" + minWeight);
// 设置为已被访问
visited[h2] = 1;
// 重置变量进行下一条路的选择
h1 = -1;
h2 = -1;
minWeight = dv;
}
}
}
/**
* 图对象
*/
class MyGraph {
/**
* 图节点个数
*/
int num;
/**
* 节点数据,如: A,B,C...
*/
char[] nodeArray;
/**
* 使用二维数组(矩阵)表示每个节点的关系(路程长度)
*/
int[][] weight;
/**
* 构造器
*
* @param num
*/
public MyGraph(int num) {
this.num = num;
this.nodeArray = new char[num];
this.weight = new int[num][num];
}
}