生活随笔
收集整理的這篇文章主要介紹了
实验1 最小生成树问题【Kruskal+Prim】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1.貪心算法思想
貪心算法的基本思想是找出整體當中每個小的局部的最優解,并且將所有的這些局部最優解合起來形成整體上的一個最優解。因此能夠使用貪心算法的問題必須滿足下面的兩個性質:
1.整體的最優解可以通過局部的最優解來求出; 2.一個整體能夠被分為多個局部,并且這些局部都能夠求出最優解。
2.貪心算法的基本策 略 :
1、從問題的某個初始解出發。 2、采用循環語句,當可以向求解目標前進一步時,就根據局部最優策略,得到一個部分解,縮小問題的范圍或規模。 3、將所有部分解綜合起來,得到問題的最終解。
(2-1)Kruskal算法
將所有邊按照權值的大小進行升序排序,然后從小到大一一判斷,條件為:如果這個邊不會與之前選擇的所有邊組成回路,就可以作為最小生成樹的一部分;反之,舍去。直到具有 n 個頂點的連通網篩選出來 n-1 條邊為止。篩選出來的邊和所有的頂點構成此連通網的最小生成樹。
(2-2)Prim算法
Prim算法從任意一個頂點開始,每次選擇一個與當前頂點集最近的一個頂點,并將兩頂點之間的邊加入到樹中。
3.數據結構 Prim算法:
a. 在一個加權連通圖中,頂點集合V,邊集合為E b. 任意選出一個點作為初始頂點,標記為visit,計算所有與之相連接的點的距離,選擇距離最短的,標記visit. c. 重復以下操作,直到所有點都被標記為visit: 在剩下的點鐘,計算與已標記visit點距離最小的點,標記visit,證明加入了最小生成樹。
Kruskal算法
a.假定拓撲圖的邊的集合是E,初始化最小生成樹邊集合G={}。 b. 遍歷集合E中的所有元素,并且按照權值的大小進行排序。 c. 找出E中權值最小的邊e 。 d .如果邊e不和最小生成樹集合G中的邊構成環路,則將邊e加到邊集合G中;否則測試下一條權值次小的邊,直到滿足條件為止。 e. 重復步驟b,直到G=E。
4.數據模型
5.程序代碼 Kruskal算法Java代碼實現
public class Kruskal { public int edgeNums
; public char [ ] data
; public int [ ] [ ] matrix
; private static final int INF
= Integer . MAX_VALUE
; public Kruskal ( char [ ] data
, int [ ] [ ] matrix
) { int length
= data
. length
; this . data
= new char [ length
] ; this . matrix
= new int [ length
] [ length
] ; for ( int i
= 0 ; i
< length
; i
++ ) { this . data
[ i
] = data
[ i
] ; } for ( int s
= 0 ; s
< length
; s
++ ) { for ( int k
= 0 ; k
< length
; k
++ ) { this . matrix
[ s
] [ k
] = matrix
[ s
] [ k
] ; } } for ( int m
= 0 ; m
< length
; m
++ ) { for ( int n
= m
+ 1 ; n
< length
; n
++ ) { if ( matrix
[ m
] [ n
] != INF
) { this . edgeNums
++ ; } } } } public Edge [ ] getEdges ( ) { int length
= this . data
. length
; int index
= 0 ; Edge [ ] edges
= new Edge [ this . edgeNums
] ; for ( int m
= 0 ; m
< length
; m
++ ) { for ( int n
= m
+ 1 ; n
< length
; n
++ ) { if ( matrix
[ m
] [ n
] != INF
) { edges
[ index
] = new Edge ( data
[ m
] , data
[ n
] , matrix
[ m
] [ n
] ) ; index
++ ; } } } return edges
; } public void sortEdges ( Edge [ ] edges
) { for ( int k
= 0 ; k
< edges
. length
- 1 ; k
++ ) { for ( int s
= 0 ; s
< edges
. length
- k
- 1 ; s
++ ) { if ( edges
[ s
] . weight
> edges
[ s
+ 1 ] . weight
) { Edge temp
= edges
[ s
] ; edges
[ s
] = edges
[ s
+ 1 ] ; edges
[ s
+ 1 ] = temp
; } } } } public void kruskal ( ) { Edge [ ] edges
= getEdges ( ) ; sortEdges ( edges
) ; Edge [ ] result
= new Edge [ edgeNums
] ; int [ ] ends
= new int [ edgeNums
] ; int index
= 0 ; for ( int k
= 0 ; k
< edgeNums
; k
++ ) { int front
= getPosition ( edges
[ k
] . front
) ; int after
= getPosition ( edges
[ k
] . after
) ; int m
= getEnd ( ends
, front
) ; int n
= getEnd ( ends
, after
) ; if ( m
!= n
) { ends
[ m
] = n
; result
[ index
++ ] = edges
[ k
] ; } } System . out
. println ( Arrays . toString ( result
) ) ; } public int getEnd ( int [ ] ends
, int k
) { while ( ends
[ k
] != 0 ) { k
= ends
[ k
] ; } return k
; } private int getPosition ( char ch
) { for ( int i
= 0 ; i
< data
. length
; i
++ ) { if ( data
[ i
] == ch
) { return i
; } } return - 1 ; } public void printMatrix ( ) { System . out
. println ( "二維矩陣列表為:" ) ; for ( int [ ] cur
: matrix
) { System . out
. println ( Arrays . toString ( cur
) ) ; } System . out
. println ( "邊的大小為:" + this . edgeNums
) ; } / / main測試
public static void main ( String [ ] args
) { char [ ] vertex
= { 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' } ; int [ ] [ ] matrix
= { { 0 , 12 , INF
, INF
, INF
, 16 , 14 } , { 12 , 9 , 10 , INF
, INF
, 7 , INF
} , { INF
, 10 , 0 , 3 , 5 , 6 , INF
} , { INF
, INF
, 3 , 0 , 4 , INF
, INF
} , { INF
, INF
, 5 , 4 , 0 , 2 , 8 } , { 16 , 7 , 6 , INF
, 2 , 0 , 9 } , { 14 , INF
, INF
, INF
, 8 , 9 , 0 } } ; Kruskal kruskal
= new Kruskal ( vertex
, matrix
) ; kruskal
. printMatrix ( ) ; kruskal
. kruskal ( ) ; }
} class Edge { public char front
; public char after
; public int weight
; public Edge ( char front
, char after
, int weight
) { this . front
= front
; this . after
= after
; this . weight
= weight
; } @Override public String toString ( ) { return "Edge{" + "front=" + front
+ ", after=" + after
+ ", weight=" + weight
+ '}' ; }
} Prim 算法
Java 代碼實現
public class Prim { public static void main ( String [ ] args
) { char [ ] data
= { 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' } ; int nodes
= data
. length
; int [ ] [ ] weight
= { { 10000 , 5 , 7 , 10000 , 10000 , 10000 , 2 } , { 5 , 10000 , 10000 , 9 , 10000 , 10000 , 3 } , { 7 , 10000 , 10000 , 10000 , 8 , 10000 , 10000 } , { 10000 , 9 , 10000 , 10000 , 10000 , 4 , 10000 } , { 10000 , 10000 , 8 , 10000 , 10000 , 5 , 4 } , { 10000 , 10000 , 10000 , 4 , 5 , 10000 , 6 } , { 2 , 3 , 10000 , 10000 , 4 , 6 , 10000 } , } ; MinTree minTree
= new MinTree ( ) ; Graph graph
= new Graph ( nodes
) ; minTree
. createGraph ( nodes
, data
, weight
, graph
) ; minTree
. showGraph ( graph
) ; minTree
. prim ( graph
, 0 ) ; }
} class MinTree { public void createGraph ( int nodes
, char [ ] data
, int [ ] [ ] weight
, Graph graph
) { int i
, j
; for ( i
= 0 ; i
< nodes
; i
++ ) { graph
. data
[ i
] = data
[ i
] ; for ( j
= 0 ; j
< nodes
; j
++ ) { graph
. weight
[ i
] [ j
] = weight
[ i
] [ j
] ; } } } public void prim ( Graph graph
, int v
) { int x1
= - 1 , x2
= - 1 ; int nodeNums
= graph
. nodes
; int [ ] visited
= new int [ nodeNums
] ; visited
[ v
] = 1 ; int minWeight
= 10000 ; for ( int k
= 1 ; k
< nodeNums
; k
++ ) { for ( int al
= 0 ; al
< nodeNums
; al
++ ) { for ( int not
= 0 ; not
< nodeNums
; not
++ ) { if ( visited
[ al
] == 1 && visited
[ not
] == 0 && graph
. weight
[ al
] [ not
] < minWeight
) { minWeight
= graph
. weight
[ al
] [ not
] ; x1
= al
; x2
= not
; } } } visited
[ x2
] = 1 ; minWeight
= 10000 ; System . out
. println ( "邊<" + graph
. data
[ x1
] + "-" + graph
. data
[ x2
] + ">" + "權值為:" + graph
. weight
[ x1
] [ x2
] ) ; } } public void showGraph ( Graph graph
) { for ( int [ ] cur
: graph
. weight
) { System . out
. println ( Arrays . toString ( cur
) ) ; } }
} class Graph { protected int nodes
; protected char [ ] data
; protected int [ ] [ ] weight
; public Graph ( int nodes
) { this . nodes
= nodes
; data
= new char [ nodes
] ; weight
= new int [ nodes
] [ nodes
] ; }
}
6.測試 (1)Kruskal算法測試數據如下
(其中的INF表示兩頂點之間不通)
控制臺結果如下:
(2)Prim算法測試數據如下:
(1000表示兩個頂點不連通,也可也和上面的Kruskal算法一樣使用int的最大值65535表示) 控制臺結果如下:
7.結果分析: Prim 通過鄰接矩陣圖表示的簡易實現中,找到所有最小權邊共需O(V)的運行時間。使用簡單的二叉堆與鄰接表來表示的話,普里姆算法的運行時間則可縮減為O(ElogV),其中E為連通圖的邊數,V為頂點數。如果使用較為復雜的斐波那契堆,則可將運行時間進一步縮短為O(E+VlogV),這在連通圖足夠密集時,可較顯著地提高運行速度
Kruskal 克魯斯卡爾算法的時間復雜度主要由排序方法決定,而克魯斯卡爾算法的排序方法只與網中邊的條數有關,而與網中頂點的個數無關,當使用時間復雜度為O(elog2e)的排序方法時,克魯斯卡爾算法的時間復雜度即為O(log2e),因此當網的頂點個數較多、而邊的條數較少時,使用克魯斯卡爾算法構造最小生成樹效果較好
總結
以上是生活随笔 為你收集整理的实验1 最小生成树问题【Kruskal+Prim】 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。