最小生成樹之克魯斯卡爾演算法
阿新 • • 發佈:2020-08-21
演算法思路
- 準備:邊類,圖類;
- 根據圖的鄰接矩陣獲得邊集合,並將邊按照邊的權值進行排序(升序);
- 依次取邊集合中的邊,如果取出來的這條邊不和已經選擇的邊構成迴路就新增這條邊,否則取邊集合中的下一條邊。
Q:怎麼判斷新取的邊和已經選取的邊會不會構成迴路?
A:引入一個數組,記錄每個頂點的終點,如果新取的這條邊的兩端的終點相同,說明構成迴路;否則不構成。
注:終點是指在最小生成樹中與它連通的最大頂點。
程式碼實現
package com.ex.kruskal; import java.util.ArrayList; import java.util.Collections; importjava.util.List; public class Kruskal{
static final int INF=10000; //邊 static class Edge implements Comparable<Edge>{ int p1; int p2; int weight; public Edge(int p1, int p2, int weight) { this.p1 = p1; this.p2 = p2; this.weight = weight; } @Override public int compareTo(Edge o) { return this.weight-o.weight; } } //圖 static class Graph{ char[] nodes; int[][] matrix; List<Edge> edges; public Graph(char[] nodes, int[][] matrix) {this.nodes = nodes; this.matrix = matrix; generateEdges(); } //生成邊,並排序 public void generateEdges(){ edges=new ArrayList<>(); for (int i = 0; i < nodes.length; i++) { for (int j = i+1; j < nodes.length; j++) { if (matrix[i][j]!=INF) { edges.add(new Edge(i,j,matrix[i][j])); } } } Collections.sort(edges); } } //生成最小生成樹 public static void kruskal(Graph graph){ //準備 char[] nodes = graph.nodes; List<Edge> edges = graph.edges; int[][] matrix = graph.matrix; int[] ends=new int[nodes.length]; //每次選擇一個邊,如果不構成迴路就加入集合,否則下一條邊 for (int i = 0; i < edges.size(); i++) { Edge edge = edges.get(i); int end1 = getEnd(ends, edge.p1); int end2 = getEnd(ends, edge.p2); if (end1!=end2) { System.out.println(nodes[edge.p1]+"—>"+nodes[edge.p2]+":"+matrix[edge.p1][edge.p2]); ends[end1]=end2; } } } //獲得某個頂點的終點 private static int getEnd(int[] ends,int index){ while (ends[index]!=0){ index=ends[index]; } return index; } public static void main(String[] args) { char[] vertexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; //克魯斯卡爾演算法的鄰接矩陣 int matrix[][] = { { 0, 12, INF, INF, INF, 16, 14}, { 12, 0, 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}}; //求最小生成樹 Graph graph = new Graph(vertexs, matrix); kruskal(graph); } }
普里姆演算法 VS 克魯斯卡爾演算法
n:結點數 E:邊數
演算法名 | 普里姆演算法 | 克魯斯卡爾演算法 |
---|---|---|
時間複雜度 | O(n2) | O(ElogE) |
適用範圍 |
稠密圖 (n、E相當) |
稀疏圖 (E<<n) |