連通圖的最小生成樹java
生成樹定義:node
無向連通圖G的極小連通子圖,稱爲它的生成樹。(n個頂點,n-1條邊)算法
考慮一下下面這個圖數組
上圖是一個徹底圖,它的生成樹不是惟一的,咱們列出最特殊的兩種狀況dom
上面2個圖都是第一個徹底圖的生成樹,可是2者是徹底不一樣的。測試
按照深度優先遍歷生成的生成樹,稱爲深度優先生成樹this
按照廣度優先遍歷生成的生成樹,稱爲廣度優先生成樹對象
非連通圖的生成森林,概念比較簡單,無非就是非連通圖的極大連通子圖和生成樹的概念疊加排序
最小生成樹get
圖G是帶權的無向連通圖,生成樹上個邊權值之和稱爲生成樹的代價,代價最小的生成樹稱爲最小生成樹。
最小生成樹的生成算法
Prim算法
現有連通圖G=(V, E),其最小連通圖TG=(TV, TE)。
初始狀態下:V = {V0, V1, V2 ... Vn}; TV = {}
從V當中任選一頂點,插入TV,V = {V0, V1, V2 ... Vn}; TV = {V0}
找鏈接TV和V-TV這兩個集合的權值最小的邊,插入TE,並把該邊2頂點當中本來不屬於TV的頂點加入TV;
重複上一步驟
知道V = TV
下面是java實現,首先咱們須要修改一下以前的生成圖的代碼,咱們生成了一棵7個頂點的徹底圖,每一條邊的權值是100之內的隨機數。
Graph graph = new Graph();
String nodeNames[] = {"aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg"};
for (String s : nodeNames) {
graph.nodes.add(new Node(s));
}
graph.arcs = new int[nodeNames.length][nodeNames.length];
Random ra = new Random();
for (int i = 0; i < graph.nodes.size(); i ++){
for (int j = 0; j < graph.nodes.size(); j ++){
if (i != j){
graph.arcs[i][j] = ra.nextInt(100) + 1;
}
}
}
而後是最小生成樹的Prim算法實現,解釋一下,首先建立一個二維數組表示邊,把空間都分配好,只等着往裏面填數就行。而後是一個TreeMap對象,來保存頂點,之因此用TreeMap,是爲了保證新圖的頂點順序和原圖是一致的。剩下的基本就是跟前面算法描述的差很少,你們對着看就行,沒什麼太難的地方。
public Graph getMinTree(){
int newArcs[][] = new int[this.nodes.size()][this.nodes.size()];
Map<Integer, Node> newNodes = new TreeMap<Integer, Node>();
newNodes.put(0, this.nodes.get(0));
while(newNodes.size() != this.nodes.size()){
int minWeight = 99999;
int minI = -1;
int minJ = -1;
for(int i : newNodes.keySet()){
for (int j = 0; j < this.nodes.size(); j ++){
if (i != j && !newNodes.containsKey(j)){
if (this.arcs[i][j] < minWeight){
minWeight = this.arcs[i][j];
minI = i;
minJ = j;
}
}
}
}
newNodes.put(minJ, this.nodes.get(minJ));
newArcs[minI][minJ] = minWeight;
newArcs[minJ][minI] = minWeight;
}
Graph res = new Graph();
res.arcs = newArcs;
res.nodes.addAll(newNodes.values());
return res;
}
下面有一次測試的輸出,2個圖,分別是原圖的全部權值信息,另外一個是最小生成樹的權值信息
而後還能夠用連通圖的dfs算法檢查一下。
Kruskal算法
先將全部邊按照權值,從小到大排序
依次訪問各邊,若是生成迴路,則捨棄,不然加入生成樹,同時將該邊的另外一頂點加入生成樹
直到全部頂點被加入
java實現,省略。