普里姆算法
@anthor:QYX
普里姆算法在找最小生成樹時,將頂點分為兩類,一類是在查找的過程中已經包含在樹中的(假設為 A 類),剩下的是另一類(假設為 B 類)。
對於給定的連通網,起始狀態全部頂點都歸為 B 類。在找最小生成樹時,選定任意一個頂點作為起始點,並將之從 B 類移至 A 類;然后找出 B 類中到 A 類中的頂點之間權值最小的頂點,將之從 B 類移至 A 類,如此重復,直到 B 類中沒有頂點為止。所走過的頂點和邊就是該連通圖的最小生成樹。
例如,通過普里姆算法查找圖 2(a)的最小生成樹的步驟為:
假如從頂點A出發,頂點 B、C、D 到頂點 A 的權值分別為 2、4、2,所以,對於頂點 A 來說,頂點 B 和頂點 D 到 A 的權值最小,假設先找到的頂點 B:

繼續分析頂點 C 和 D,頂點 C 到 B 的權值為 3,到 A 的權值為 4;頂點 D 到 A 的權值為 2,到 B 的權值為無窮大(如果之間沒有直接通路,設定權值為無窮大)。所以頂點 D 到 A 的權值最小:

最后,只剩下頂點 C,到 A 的權值為 4,到 B 的權值和到 D 的權值一樣大,為 3。所以該連通圖有兩個最小生成樹:

另一個例子:
package com.qyx.Tree; import java.util.Arrays; /** * prim算法最小生成樹解決修路問題 * @author Administrator * */ public class PrimAlgorithm { public static void main(String[] args) { //測試圖是否創建成功 char[] data=new char[]{'A','B','C','D','E','F','G'}; int verxs=data.length; //鄰接矩陣使用二維數組表示 int[][] weight=new int[][]{ //A B C D E F G {10000,5,7,10000,10000,10000,2}, //A {5,10000,10000,9,10000,10000,3}, //B {7,10000,10000,10000,8,10000,10000}, //C {10000,9,10000,10000,10000,4,10000}, //D {10000,10000,8,10000,10000,5,4}, //E {10000,10000,10000,4,5,10000,6}, //F {2,3,10000,10000,4,6,10000}, //G }; MGraph mgraph=new MGraph(verxs); MinTree minTree=new MinTree(); minTree.createGraph(mgraph, verxs, data, weight); minTree.showGraph(mgraph); //測試普利姆算法 minTree.prim(mgraph, 0); } } //創建最小生成樹->村庄的圖 class MinTree{ //創建圖的鄰接矩陣 /** * * @param graph 圖對象 * @param verxs 圖對應的頂點個數 * @param data 圖的各個頂點的值 * @param weight 圖的領結矩陣 */ public void createGraph(MGraph graph,int verxs,char data[],int[][] weight) { int i,j; for(i=0;i<verxs;i++) //定點 { graph.data[i]=data[i]; for(j=0;j<verxs;j++) { graph.weight[i][j]=weight[i][j]; } } } //顯示圖的鄰接矩陣 public void showGraph(MGraph graph) { for(int[] link:graph.weight) { System.out.println(Arrays.toString(link)); } } //編寫prim算法,得到最小生成樹 /** * * @param graph 圖 * @param v 表示從圖的第幾個頂點開始生成 */ public void prim(MGraph graph,int v) { //標記節點是否被訪問過 boolean visited[]=new boolean[graph.verx]; for(int i=0;i<graph.verx;i++) { visited[i]=false; } //把當前這個節點標記為已訪問 visited[v]=true; //h1和h2記錄兩個頂點的下標 int h1=-1; int h2=-1; int minWeight=10000;//將其先初始為一個大數,后面在遍歷過程中會被替換 //確定每一次生成的子圖和哪個節點距離最近 for(int k=1;k<graph.verx;k++){ //在n個節點下,會有n-1條邊 for(int i=0;i<graph.verx;i++) //i表示被訪問過的結點 { for(int j=0;j<graph.verx;j++) //j結點表示還沒有訪問過的結點 { if(visited[i]==true&&visited[j]==false&&graph.weight[i][j]<minWeight) { //替換minWeight(尋找已經訪問過的結點和未訪問過的結點間的權值最小的邊) minWeight=graph.weight[i][j]; h1=i; h2=j; } } } //找了一條邊是最小的,將當前這個結點標記為已經訪問 System.out.println(h1+"->"+h2+"權值為"+minWeight); visited[h2]=true; //minWeight重新設置為最大值 minWeight=10000; } } } class MGraph{ int verx;//表示圖的節點個數 char[] data;//存放節點的數據 int[][] weight;//存放邊,就是我們的鄰接矩陣 public MGraph(int verx) { this.verx=verx; data=new char[verx]; weight=new int[verx][verx]; } }