最小生成樹Prim演算法java實現
阿新 • • 發佈:2018-12-02
package prim;
import java.util.*;
public class PrimTest {
public static void main(String[] args) {
//互動輸入圖的鄰接矩陣表示,為方便測試,直接給定了鄰接矩陣值
// System.out.println("請輸入圖定點個數: ");
// Scanner sc = new Scanner(System.in);
// String line = sc.nextLine();
// int n = Integer.parseInt(line);
// System.out.println("請輸入圖的路徑長度: ");
// int[][] c = new int[n+1][n+1];
// for(int i = 0; i < n; i++) {
// line = sc.nextLine();
// String[] ds = line.split(",");
// for(int j = 0;j < ds.length; j++) {
// c[i+1][i+1] = Integer.parseInt(ds[j]);
//
// }
// }
// System.out.println("一次構成樹的邊為: ");
int n = 6;
//c[i][j]表示從i到j的權,
自己到自己的權,以及不能直接到的值置- 1,方便後面處理
int[][] c = {
{0,0,0,0,0,0},
{0,-1,6,1,5,-1,-1},
{0,6,-1,5,-1,3,-1},
{0,1,5,-1,5,6,4},
{0,5,-1,5,-1,-1,2},
{0,-1,3,6,-1,-1,6},
{0,-1,-1,4,2,6,-1}
};
prim(n,c);
}
public static void prim(int n, int[][] c) {
//lowcost[i] 表示 從1到i的最短權值
int[] lowcost = new int[n+1];
//closest[i]的表示:
將整個節點空間定為V,已選的空間從S=1(只有第一個點)開始,
j在V-S中,找到S裡離j最近的節點i ,就記錄在closest[j]。
int[] closest = new int[n+1];
//哪些節點已經進入S空間
boolean[] s = new boolean[n+1];
//節點1進入S中,此為初始化
s[1] = true;
//初始化
for(int i = 2; i <= n; i++) {
//初始化第一個節點到每個節點權值
lowcost[i] = c[1][i];
//初始化,因為S中只有1,所以每個V-S中的節點最近的S中的節點一定是1
closest[i] = 1;
//這些節點都初始化為不在S中的狀態
s[i] = false;
}
//n-1次遍歷,把S空間擴充成V
for(int i = 1;i < n; i++) {
//記錄一個當前最小權值,不斷比較最終變為整個1次遍歷過程的最小權值
int min = Integer.MAX_VALUE;
//初始化j,j其實代表的是V-S空間中被選進S的節點
//它的特徵是,它到S(任何節點)的權值比其他節點到S(同樣隨便哪個節點)都小
//這裡的思想就是貪心的概念,通過區域性最優可以得到全域性最優
int j = 1;
//遍歷除了直接初始化在S中的1節點外的其他所有節點
for(int k = 2; k <= n; k++) {
//不等於-1即,直接有權值,然後迭代出最小的lowcost,同時更新一些值。
//這裡舉例更容易說明,如lowcost[k]其實代表的是目前的S空間到k的最小權值,迭代找到了這個k,那麼 顯然 j就應該是k
if(lowcost[k] != -1 && lowcost[k] < min && !s[k]) {
min = lowcost[k];
j = k;
}
}
//輸出這對連線,closest[j]記錄的其實就是達成lowcost[k]這一最小權值時,S中具體是哪個節點
System.out.println(closest[j] + "-" + j);
//如此,把j納入S空間
s[j] = true;
//j進入S空間後,更新除1節點外所有節點的狀態,他們到S的最小權值還得看看他們到 新進入的j是否更小
for(int k = 2; k <= n; k++) {
if(!s[k] && c[j][k] != -1) {
//這裡注意,如果lowcost[k]本來是-1
說明本來都不相連直接可以更新了
//這裡的邏輯要搞清楚,先判斷有必要更新麼?(c[j][k]!= -1),然後判斷 要麼c[j][k]比之前的權值更小,要麼原來都不相連(c[j][k] < lowcost[k] || lowcost[k] == -1) 此時進行更新!
if(c[j][k] < lowcost[k] || lowcost[k] == -1) {
//更新該節點最小的權值
lowcost[k] = c[j][k];
//更新該節點在S中最近的點
closest[k] = j;
}
}
}
}
}
}