定义:图的生成树是它的一棵含有其所有顶点的无环连通子图,一副加权无向图的最小生成树它的一棵权值最小的生成树。
性质:
- 用一条边连接树中的任意两个顶点都会产生一个新的环
- 从树中删除任意一条边,将会得到两棵独立的树
切分定理:
切分:将图的所有顶点按照某些规则分为两个非空且没有交集的集合
横切边:连接两个属于不同集合的顶点的边
在一副加权图中,给定任意的切分,它的横切边中权重最小者必然属于图中的最小生成树。
Prim算法的切分规则:
把最小生成树中的顶点看做是一个集合,把不在最小生成树中的顶点看做是另外一个集合。
代码:
package com.chenqing.test.digraph;
import com.chenqing.test.linearList.queue.IndexMinPriorityxQueue;
import com.chenqing.test.linearList.queue.Queue;
/**
* @author 陈沁
* Prim算法实现最小生成树,主要使用的是贪心算法里的切分定理
*/
public class PrimMST {
private Edge[] edgeTo;
private Double[] weights;
private boolean[] marked;
private IndexMinPriorityxQueue<Double> qp;
public PrimMST(EdgeWeightedGraph graph) {
this.edgeTo = new Edge[graph.getV()];
this.weights = new Double[graph.getV()];
this.marked = new boolean[graph.getV()];
this.qp = new IndexMinPriorityxQueue<Double>(graph.getV());
for (int i = 0; i < this.weights.length; i++) {
this.weights[i] = Double.POSITIVE_INFINITY;
}
this.weights[0] = 0.0;
this.qp.insert(0, 0.0);
while(!this.qp.isEmpty()){
int minIndex = this.qp.delMin();
this.visit(graph, minIndex);
}
}
private void visit(EdgeWeightedGraph graph, int v){
this.marked[v] = true;
for (Edge e : graph.adj(v)) {
int w = e.other(v);
if(marked[w]){
continue;
}
if(e.getWeight() < weights[w]){
edgeTo[w] = e;
weights[w] = e.getWeight();
if(qp.contains(w)){
qp.changeItem(w, weights[w]);
}else{
qp.insert(w, weights[w]);
}
}
}
}
public Queue<Edge> edges(){
Queue<Edge> edges = new Queue<>();
for (int i = 0; i < this.edgeTo.length; i++) {
if(this.edgeTo[i] != null){
edges.enqueue(this.edgeTo[i]);
}
}
return edges;
}
}
kruskal算法:
package com.chenqing.test.digraph;
import com.chenqing.test.linearList.queue.MinPriorityQueue;
import com.chenqing.test.linearList.queue.Queue;
import com.chenqing.test.uf.UfTree;
/**
* @author 陈沁
* Kruskal算法实现最小生成树,主要使用的是贪心算法里的切分定理
*/
public class KruskalMST {
private Queue<Edge> edges; // 保存最小生成树的所有边
private UfTree uf; // 索引代表顶点,可以判断两个顶点是否在一颗树中,可以合并两个顶点到一颗树中
private MinPriorityQueue<Edge> minPriorityQueue; // 最小优先队列,存储图中的所有边
public KruskalMST(EdgeWeightedGraph graph) {
this.edges = new Queue<Edge>();
this.uf = new UfTree(graph.getV());
this.minPriorityQueue = new MinPriorityQueue<>(graph.getE() + 1);
for (Edge edge : graph.edges()) {
minPriorityQueue.insert(edge);
}
while (!minPriorityQueue.isEmpty() && edges.size() <= graph.getV() - 1){
Edge edge = minPriorityQueue.delMin();
int either = edge.either();
int other = edge.other(either);
if(uf.connected(either, other)){
continue;
}
edges.enqueue(edge);
uf.union(either, other);
}
}
public Queue<Edge> edges(){
return edges;
}
}