最小生成树定义:
每一个无向图可拆分成多个子图,在这些子图中,如果图的各个顶点没有形成回路,则是图的一颗生成树。
最小生成树的意识是树的相邻节点距离之和最小。
应用场景:
张三被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。
张三已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。为了用最小的消费,他想铺设最短的光纤去连接所有的农场,问要如何实现。
算法实现:
有关最小生成树的问题常见的算法有两种,分别是Kruskal(克鲁斯卡尔)算法和Prim(普里姆)算法,本文讲解Kruskal算法的实现
Kruskal算法的计算流程大致如下:
1.将无向图的边按距离长短递增式排序,放到集合中
2.遍历该集合,找出最短的边,加入到结果生成树的集合中
3.如果结果生成树出现回路,则放弃这条边
4.重新执行步骤2,直至所有顶点被遍历
可以看出在每次遍历过程中采用了贪心算法
算法实例图:
代码实现:
Edge类用与封装无向图中每条边的信息
public class Edge implements Comparable<Edge>{
private String start;
private String end;
private int distance;
public Edge(String start,String end,int distance){
this.start=start;
this.end=end;
this.distance=distance;
}
public String getStart() {
return start;
}
public void setStart(String start) {
this.start = start;
}
public String getEnd() {
return end;
}
public void setEnd(String end) {
this.end = end;
}
public int getDistance() {
return distance;
}
public void setDistance(int distance) {
this.distance = distance;
}
@Override
public String toString() {
return start + "->" + end;
}
@Override
public int compareTo(Edge obj) {
int targetDis=obj.getDistance();
return distance>targetDis?1:(distance==targetDis?0:-1);
}
}
MapBuilder类用于构建数据源(数据源结构如上图所示):
public class MapBuilder {
public TreeSet<Edge> build(){
TreeSet<Edge> edges=new TreeSet<Edge>();
edges.add(new Edge("A","B",1));
edges.add(new Edge("A","C",4));
edges.add(new Edge("A","F",6));
edges.add(new Edge("B","D",8));
edges.add(new Edge("B","E",3));
edges.add(new Edge("C","F",5));
edges.add(new Edge("C","E",9));
edges.add(new Edge("D","E",7));
edges.add(new Edge("D","F",10));
edges.add(new Edge("E","F",2));
return edges;
}
public int getPointNum(){
return 6;
}
}
Kruskal类用于计算最小生成树
public class Kruskal {
private Set<String> points=new HashSet<String>();
private List<Edge> treeEdges=new ArrayList<Edge>();
public void buildTree(){
MapBuilder builder=new MapBuilder();
TreeSet<Edge> edges=builder.build();
int pointNum=builder.getPointNum();
for(Edge edge:edges){
if(isCircle(edge)){
continue;
}else{//没有出现回路,将这条边加入treeEdges集合
treeEdges.add(edge);
//如果边数等于定点数-1,则遍历结束
if(treeEdges.size()==pointNum-1){
return;
}
}
}
}
public void printTreeInfo(){
int totalDistance=0;
for(Edge edge:treeEdges){
totalDistance+=edge.getDistance();
System.out.println(edge.toString());
}
System.out.println("总路径长度:"+totalDistance);
}
private boolean isCircle(Edge edge){
int size=points.size();
if(!points.contains(edge.getStart())){
size++;
}
if(!points.contains(edge.getEnd())){
size++;
}
if(size==treeEdges.size()+1){
return true;
}else{
points.add(edge.getStart());
points.add(edge.getEnd());
return false;
}
}
}
Main类用于测试Kruskal算法
public class Main {
public static void main(String[] args) {
Kruskal test=new Kruskal();
test.buildTree();
test.printTreeInfo();
}
}
打印输出:
A->B
E->F
B->E
A->C
D->E
总路径长度:17