最小生成树
最小生成树
A minimum spanning tree of a weighted, connected graph is a subgraph in which a tree connects all the vertices together and has the minimum weight.
Prime's Algorithm
Prime's algorithm is a greedy algorithm that finds a minimum spanning tree for a undirected graph.
algorithm description
- Starts from one vertex, select the least weight edge of that vertex;
- Add a new vertex that connects with the visited vertices with the least weight edge;
- Repeated until all vertices are visited
time complexity: O(|V|2)
Definition of Edge
class Edge{ int from; int to; int weight; Edge(int u,int v,int w){ from=u; to=v; weight=w; } }
initialize a graph
public static ArrayList<ArrayList<Edge>> createGraph(Edge[] edges, int nodes) { ArrayList<ArrayList<Edge>> graph = new ArrayList<>(); for(int i=0; i<nodes; i++) graph.add(new ArrayList<>()); for(Edge source:edges) { Edge destination = new Edge(source.from, source.to, source.weight); graph.get(source.from).add(source); graph.get(source.to).add(destination); } return graph; }
Prime
PriorityQueue is an ordered queue. Here is used to store all the connected edges to visited nodes in increasing order (by weight).
public static ArrayList<Edge> prims(ArrayList<ArrayList<Edge>> graph){ //to store MST ArrayList<Edge> MST = new ArrayList<>(); //ordered queue, increasing order PriorityQueue<Edge> pq = new PriorityQueue<>((Edge edge1, Edge edge2) -> { if (edge1.weight < edge2.weight) return -1; else if(edge1.weight > edge2.weight) return 1; else return 0; }); pq.addAll(graph.get(0)); double cost = 0; boolean[] visited = new boolean[graph.size()]; visited[0]=true; while(!pq.isEmpty()){ Edge current=pq.poll(); // if both nodes are visited, skip the round if(visited[current.to]&&visited[current.from]) continue; for(Edge adjacency:graph.get(current.to)){ if(!visited[adjacency.to]) pq.add(adjacency); } visited[current.to]=true; cost=cost+current.weight; MST.add(current); } return MST; }
Kruskal's Algorithm
algorithm description
- Sort the graph edges with respect to their weights in increasing order;
- Add edges to MST with least weight in a single round (make sure the added edges don't form a cycle--adding edges which only connect the disconnected components)
time complexity: O(|E|log|E|)
Pseudocode
MST- KRUSKAL (G, w)
1. A ← ∅
2. for each vertex v ∈ V [G]
3. do MAKE - SET (v)
4. sort the edges of E into non decreasing order by weight w
5. for each edge (u, v) ∈ E, taken in non decreasing order by weight
6. do if FIND-SET (μ) ≠ if FIND-SET (v)
7. then A ← A ∪ {(u, v)}
8. UNION (u, v)
9. return A
并查集的概念
function find() is to find the parent of one node, to make sure two nodes from different unions, and thus to check whether adding this edge will create a cycle.
function find() is to make two nodes have the same parent after their included edge is addpublic void kruskalMST(){
PriorityQueue<Edge> pq = new PriorityQueue<>((Edge e1,Edge e2) -> { return Integer.compare(e1.weight,e2.weight); }); pq.addAll(allEdges); int [] parent = new int[vertices]; for (int i = 0; i <vertices ; i++) { parent[i] = i; } ArrayList<Edge> MST = new ArrayList<>(); int index = 0; while(index<vertices-1){ Edge edge = pq.poll(); //check if adding this edge creates a cycle // two nodes must from different unions int x_set = find(parent, edge.from); int y_set = find(parent, edge.to); if(x_set!=y_set) { MST.add(edge); index++; union(parent, x_set, y_set); } } } public int find(int [] parent, int vertex){ //chain of parent pointers from x upwards through the tree // until an element is reached whose parent is itself if(parent[vertex]!=vertex) return find(parent, parent[vertex]);; return vertex; } public void union(int [] parent, int x, int y){ int x_set_parent = find(parent, x); int y_set_parent = find(parent, y); //make x as parent of y parent[y_set_parent] = x_set_parent; }
Summary
Prime starts from nodes. Generating MST by spanning edges from the visited nodes.
By contrast, Kruskal starts from edges, always choose the min weight edges and avoid cycles.