本文實(shí)例講述了Java貪心算法之Prime算法原理與實(shí)現(xiàn)方法。分享給大家供大家參考,具體如下:
Prime算法:是一種窮舉查找算法來(lái)從一個(gè)連通圖中構(gòu)造一棵最小生成樹(shù)。利用始終找到與當(dāng)前樹(shù)中節(jié)點(diǎn)權(quán)重最小的邊,找到節(jié)點(diǎn),加到最小生成樹(shù)的節(jié)點(diǎn)集合中,直至所有節(jié)點(diǎn)都包括其中,這樣就構(gòu)成了一棵最小生成樹(shù)。prime在算法中屬于貪心算法的一種,貪心算法還有:Kruskal、Dijkstra以及哈夫曼樹(shù)及編碼算法。
下面具體講一下prime算法:
1、首先需要構(gòu)造一顆最小生成樹(shù),以及兩個(gè)節(jié)點(diǎn)之間的權(quán)重?cái)?shù)組,在此我們用一個(gè)二維數(shù)組來(lái)代表這樣一個(gè)連通圖的形式。節(jié)點(diǎn)就是0~數(shù)組長(zhǎng)度-1,10000代表節(jié)點(diǎn)本身,權(quán)重 >= 100代表兩個(gè)節(jié)點(diǎn)不連通,反之連通。
構(gòu)建連通圖代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// 初始化連通圖 public static void initGraph( int [][] graph, ArrayList<Integer> points) { for ( int i = 0 ; i < graph.length; i++) { points.add(i); for ( int j = 0 ; j < graph[i].length; j++) { if (i == j) { graph[i][j] = 10000 ; } else { int temp = ( int )(Math.random() * 200 + 1 ); graph[i][j] = temp; // 大于等于100不連通, 小于100連通 } graph[j][i] = graph[i][j]; } } } |
連通圖的數(shù)組表示:
2、找到距離當(dāng)前樹(shù)中節(jié)點(diǎn)權(quán)重最小的邊,開(kāi)始節(jié)點(diǎn)隨機(jī)產(chǎn)生,(算法的重點(diǎn))!!!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
// prime算法實(shí)現(xiàn) public static int prime( int [][] graph, ArrayList<Integer> points, int current) { String path = "" ; ArrayList<Integer> selectPoints = new ArrayList<Integer>(); // 選中的點(diǎn)集合 int totalWeights = 0 ; // 權(quán)重總和 selectPoints.add(current); // 添加初始開(kāi)始節(jié)點(diǎn) points.remove(current); // 從未選擇的節(jié)點(diǎn)集合中刪除被選中的節(jié)點(diǎn) path = "|" + current + "|" ; System.out.println( "當(dāng)前路徑:" + path); System.out.println( "當(dāng)前已選中節(jié)點(diǎn): " + selectPoints.toString()); System.out.println( "當(dāng)前剩余節(jié)點(diǎn): " + points.toString()); System.out.println( "當(dāng)前總權(quán)重: " + totalWeights); // 循環(huán)找出最小權(quán)重的邊 直至所有的點(diǎn)都被選中 while (points.size() > 0 ) { // 遍歷選中的點(diǎn)相連的邊中權(quán)重最小的邊記錄下來(lái) int mincost = 0 ; // 最小權(quán)重 int mincostPoint = selectPoints.get( 0 ); // 最小權(quán)重邊對(duì)應(yīng)的點(diǎn) List<Integer> linePoints = new ArrayList<Integer>(); // 記錄所有與已選中點(diǎn)相連的點(diǎn) for ( int i = 0 ; i < selectPoints.size(); i++) { for ( int j = 0 ; j < points.size(); j++) { int startPoint = selectPoints.get(i); // 起點(diǎn) int endPoint = points.get(j); // 終點(diǎn) // 兩點(diǎn)是相連的 if (graph[startPoint][endPoint] != 10000 && graph[startPoint][endPoint] < 100 ) { // 將和已選中點(diǎn)連通的點(diǎn)加入連通集合 linePoints.add(points.get(j)); if (linePoints.size() == 1 ) { // 將第一個(gè)連通的邊的權(quán)重賦值為最小權(quán)重 mincost = graph[startPoint][linePoints.get( 0 )]; // 最小權(quán)重相連的點(diǎn) mincostPoint = endPoint; } else { // 與當(dāng)前的最小權(quán)重比較 if (graph[startPoint][endPoint] < mincost) { // 最小權(quán)重相連的點(diǎn) mincost = graph[startPoint][endPoint]; mincostPoint = endPoint; } } } } } if (mincost != 0 ) { // 證明是找到了相連的點(diǎn) selectPoints.add(mincostPoint); // 添加點(diǎn) points = (ArrayList<Integer>) removeFormPoints(points, mincostPoint); // 權(quán)重增加 totalWeights += mincost; path += " ---" + mincost + "--- |" + mincostPoint + "|" ; System.out.println( "當(dāng)前路徑:" + path); } else { System.out.println( "不連通" ); return 0 ; } // 打印當(dāng)前所選中的最小權(quán)重邊對(duì)應(yīng)的點(diǎn) System.out.println( "當(dāng)前已選中節(jié)點(diǎn): " + selectPoints.toString()); System.out.println( "當(dāng)前剩余節(jié)點(diǎn): " + points.toString()); System.out.println( "當(dāng)前總權(quán)重: " + totalWeights); } System.out.println( "總路徑:" + path); // 返回總權(quán)重 return totalWeights; } // 刪除剩余節(jié)點(diǎn)中的相連通的最小權(quán)重的節(jié)點(diǎn)的方法(就是將該節(jié)點(diǎn)加入最小生成樹(shù)中) public static List<Integer> removeFormPoints(ArrayList<Integer> points, int mincostPoint) { List<Integer> tempPoints = new ArrayList<Integer>(); for ( int i = 0 ; i < points.size(); i++) { if (points.get(i) != mincostPoint) { tempPoints.add(points.get(i)); } } return tempPoints; } |
以下是算法實(shí)現(xiàn)過(guò)程的打印信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
10000 101 72 100 146 101 10000 67 64 11 72 67 10000 13 79 100 64 13 10000 111 146 11 79 111 10000 開(kāi)始所有節(jié)點(diǎn)集:[ 0 , 1 , 2 , 3 , 4 ] 開(kāi)始節(jié)點(diǎn): 1 當(dāng)前路徑:| 1 | 當(dāng)前已選中節(jié)點(diǎn): [ 1 ] 當(dāng)前剩余節(jié)點(diǎn): [ 0 , 2 , 3 , 4 ] 當(dāng)前總權(quán)重: 0 當(dāng)前路徑:| 1 | --- 11 --- | 4 | 當(dāng)前已選中節(jié)點(diǎn): [ 1 , 4 ] 當(dāng)前剩余節(jié)點(diǎn): [ 0 , 2 , 3 ] 當(dāng)前總權(quán)重: 11 當(dāng)前路徑:| 1 | --- 11 --- | 4 | --- 64 --- | 3 | 當(dāng)前已選中節(jié)點(diǎn): [ 1 , 4 , 3 ] 當(dāng)前剩余節(jié)點(diǎn): [ 0 , 2 ] 當(dāng)前總權(quán)重: 75 當(dāng)前路徑:| 1 | --- 11 --- | 4 | --- 64 --- | 3 | --- 13 --- | 2 | 當(dāng)前已選中節(jié)點(diǎn): [ 1 , 4 , 3 , 2 ] 當(dāng)前剩余節(jié)點(diǎn): [ 0 ] 當(dāng)前總權(quán)重: 88 當(dāng)前路徑:| 1 | --- 11 --- | 4 | --- 64 --- | 3 | --- 13 --- | 2 | --- 72 --- | 0 | 當(dāng)前已選中節(jié)點(diǎn): [ 1 , 4 , 3 , 2 , 0 ] 當(dāng)前剩余節(jié)點(diǎn): [] 當(dāng)前總權(quán)重: 160 總路徑:| 1 | --- 11 --- | 4 | --- 64 --- | 3 | --- 13 --- | 2 | --- 72 --- | 0 | 總權(quán)重: 160 |
該算法只是個(gè)人的理解實(shí)現(xiàn),若有其他想法或者建議,歡迎大家交流。
希望本文所述對(duì)大家java程序設(shè)計(jì)有所幫助。
原文鏈接:http://blog.csdn.net/u014455765/article/details/50217867