/**
* Prim 算法構建最小生成樹(節點必須含有權重)<br/>
*
* 當中每個頂點包含兩個標記:(1)指出了最近的樹中頂點和邊的權重; (2)被選中的頂點和邊加粗表示<br/>
*
* 加入節點u:<br/>
* (1)把u*從集合V-Vt移動到樹的頂點集合Vt中(V爲已加入樹的節點的集合,Vt爲還沒加入樹的節點的集合)<br/>
* (2)對於集合V-Vt中每一個剩下的頂點u,如果它用一條比u當前距離標記更短的變和u*相連,分別把它的標記更新爲u*以及u與u*之間的權重<br/>
* <br/>
* test: 0 3 0 6 5 3 0 1 0 4 0 1 0 0 4 6 0 0 0 2 5 4 4 2 0<br/>
* test: 0 3 0 0 6 5 3 0 1 0 0 4 0 1 0 6 0 4 0 0 6 0 8 5 6 0 0 8 0 2 5 4 4 5 2 0
*
* <br/>算法效率:<br/>鄰接矩陣,優先隊列數組 O(V^2)
* <br/>鄰接鏈表,優先隊列堆 O(ElogV)
* @author chenxuegui
*
*/
public class Prim
{
// 節點數
static int i = 6;
// 輸入5個點的權重舉證
public static void main(String[] args)
{
int[][] weight = new int[i][i];
// 初始化權重矩陣,沒有通路的以0表示
for (int k = 0; k < i * i; k++)
{
weight[k / i][k % i] = Integer.valueOf(args[k]);
}
// 用hash隊列充當優先隊列
Map<Integer, Integer> map = new HashMap<>();
// 節點輸出的順序
List<Integer> list = new ArrayList<>();
// 初始化優先隊列
for (int k = 0; k < i; k++)
{
map.put(k, k == 0 ? -1 : weight[0][k]);
}
Prim p = new Prim();
p.prim(weight, map, list, i);
for (int i : list)
{
System.out.println(i);
}
}
/**
*
* 實現prim算法的核心部分,加入權值最小的點
*
* @param weight
* @param map
* @param list
* @param i
* 節點數
* @param u
* 上一個加入節點
*/
private void prim(int[][] weight, Map<Integer, Integer> map,
List<Integer> list, int i)
{
for (int k = 0; k < i; k++)
{
Iterator<Integer> it = map.keySet().iterator();
// 取得當前優先隊列中最優選擇
int minKey = 0;
int minValue = Integer.MAX_VALUE;
while (it.hasNext())
{
int key = it.next();
if (map.get(key) < minValue && map.get(key) != 0)
{
minValue = map.get(key);
minKey = key;
}
}
// 把當前最優點(即距離最短的點)加入list中
list.add(minKey);
map.remove(minKey);
// 跟新當前優先隊列中的點的權值
it = map.keySet().iterator();
while (it.hasNext())
{
int key = it.next();
int value = map.get(key);
if ((map.get(key) > weight[minKey][key] && weight[minKey][key] != 0)
|| (map.get(key) == 0))
value = weight[minKey][key];
map.put(key, value);
}
}
}
}