Java 最小生成树算法-普里姆算法和克鲁斯卡尔算法

1.生成树与最小生成树

先介绍一下最小生成树(Minimum Cost Spanning Tree),简称MST。

  1. 给定一个带权的无向连通图,如何选取一棵生成树,使树上所有边上权的总和为最小,这叫最小生成树
  2. N个顶点,一定有N-1条边
  3. 包含全部顶点
  4. N-1条边都在图中
    Java 最小生成树算法-普里姆算法和克鲁斯卡尔算法_第1张图片
    求最小生成树的算法主要是:普里姆算法和克鲁斯卡尔算法

2.普里姆算法和克鲁斯卡尔算法

2.1普里姆算法

  1. 普利姆(Prim)算法求最小生成树,也就是在包含n个顶点的连通图中,找出只有(n-1)条边包含所有n个顶点的连通子图,也就是所谓的极小连通子图
  2. 普利姆的算法如下:
    A. 设G=(V,E)是连通网,T=(U,D)是最小生成树,V,U是顶点集合,E,D是边的集合
    B. 若从顶点u开始构造最小生成树,则从集合V中取出顶点u放入集合U中,标记顶点v的visited[u]=1
    C. 若集合U中顶点ui与集合V-U中的顶点vj之间存在边,则寻找这些边中权值最小的边,但不能构成回路,将顶点vj加入集合U中,将边(ui,vj)加入集合D中,标记visited[vj]=1
    D. 重复步骤②,直到U与V相等,即所有顶点都被标记为访问过,此时D中有n-1条边
    Java 最小生成树算法-普里姆算法和克鲁斯卡尔算法_第2张图片
    算法实现
    从图的所有边中找最短的边,该边需要符合的要求一端已经被访问,一端未被访问。
/**
 * prim算法:最小生成树的构建过程
 * @param graph
 * @param v          假定从顶点V开始
 */
public void prim(int v){
	//visited[]标记结点(顶点是否访问过)
	boolean isVisited[]=new boolean[this.verxs];
	//将当前顶点标记为已经访问
	isVisited[v]=true;
	
	//MST的边为(顶点个数-1)
	for(int k=1;k

2.2克鲁斯卡尔算法

  1. 克鲁斯卡尔(Kruskal)算法,是用来求加权连通图的最小生成树的算法。
  2. 基本思想:按照权值从小到大的顺序选择n-1条边,并保证这n-1条边不构成回路
  3. 具体做法:首先构造一个只含n个顶点的森林,然后依权值从小到大从连通网中选择边加入到森林中,并使森林中不产生回路,直至森林变成一棵树为止
    Java 最小生成树算法-普里姆算法和克鲁斯卡尔算法_第3张图片
    算法实现
    算法分为两步,找寻最短边,判断加入该边后是否构成回路。
    判断回路的方法可由判断生成树中边的个数是否大于等于点的个数来得到,如果生成树中边的个数大于等于点的个数,存在环(逆命题在不存在单独的点时成立)。
/**
 * 克鲁斯卡尔算法:最小生成树的构建过程
 */
public void kruskal(){
	int edgeNum=0;                         //边的数量
	Setverxset=new HashSet<>();   //点的集合
	//最小生成树边的个数是(顶点个数-1),以此作为循环条件
	while(edgeNum!=this.verxs-1){
		int min=Integer.MAX_VALUE;
		//找到图中最小的边
		int v1=-1;
		int v2=-1;
		for(int i=0;i

3.具体实现

普里姆算法

package primAlgorithm;
import java.util.Arrays;
/**
 * Prim算法
 * @author BayMax
 *
 */
public class PrimAlgorithm {
	public static void main(String[] args) {
		//手动创建图
		char []data={'A','B','C','D','E','F','G'};
		int verxs=data.length;
		int [][]weight=new int[][]{
			{10000,5,7,10000,10000,10000,2},
            {5,10000,10000,9,10000,10000,3},
            {7,10000,10000,10000,8,10000,10000},
            {10000,9,10000,10000,10000,4,10000},
            {10000,10000,8,10000,10000,5,4},
            {10000,10000,10000,4,5,10000,6},
            {2,3,10000,10000,4,6,10000},
		};
		
		MGraph graph=new MGraph(verxs);
		//初始化点
		graph.initGraph(verxs, data, weight);
		//测试Prime算法
		//graph.prim(0);
		MGraph mst=graph.prim_pro(0);
		mst.showGraph();
	}

}

//图
class MGraph{
	int verxs;      //表示图的结点个数
	char[] data;    //存放结点的个数
	int [][]weight; //存放边,邻接矩阵
	
	//图的构造
	public MGraph(int verxs) {
		super();
		this.verxs = verxs;
		this.data = new char[verxs];
		this.weight = new int[verxs][verxs];
	}
	
	/**
	 * 初始化图,创建图的邻接矩阵
	 * @param graph
	 * @param verxs
	 * @param data
	 * @param weight
	 */
	public void initGraph(int verxs,char []data,int[][]weight){
		for(int i=0;i

克鲁斯卡尔算法

package kruskalAlgorithm;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
 * 克鲁斯卡尔算法
 * @author BayMax
 *
 */
public class KruskalAlgorithm {
	public static void main(String[] args) {
		//手动创建图
		char []data={'A','B','C','D','E','F','G'};
		int verxs=data.length;
		int [][]weight=new int[][]{
			{10000,5,7,10000,10000,10000,2},
            {5,10000,10000,9,10000,10000,3},
            {7,10000,10000,10000,8,10000,10000},
            {10000,9,10000,10000,10000,4,10000},
            {10000,10000,8,10000,10000,5,4},
            {10000,10000,10000,4,5,10000,6},
            {2,3,10000,10000,4,6,10000},
		};
		
		MGraph graph=new MGraph(verxs);
		//初始化点
		graph.initGraph(verxs, data, weight);
		MGraph mst=graph.kruskal_pro();
		mst.showGraph();	
	}
}

//图
class MGraph{
	int verxs;      //表示图的结点个数
	char[] data;    //存放结点的个数
	int [][]weight; //存放边,邻接矩阵
	
	//图的构造
	public MGraph(int verxs) {
		super();
		this.verxs = verxs;
		this.data = new char[verxs];
		this.weight = new int[verxs][verxs];
	}
	
	/**
	 * 初始化图,创建图的邻接矩阵
	 * @param graph
	 * @param verxs
	 * @param data
	 * @param weight
	 */
	public void initGraph(int verxs,char []data,int[][]weight){
		for(int i=0;iverxset=new HashSet<>();   //点的集合
		//最小生成树边的个数是(顶点个数-1),以此作为循环条件
		while(edgeNum!=this.verxs-1){
			int min=Integer.MAX_VALUE;
			//找到图中最小的边
			int v1=-1;
			int v2=-1;
			for(int i=0;iverxset=new HashSet<>();   //点的集合
		//最小生成树边的个数是(顶点个数-1),以此作为循环条件
		while(edgeNum!=this.verxs-1){
			int min=Integer.MAX_VALUE;
			//找到图中最小的边
			int v1=-1;
			int v2=-1;
			for(int i=0;i

你可能感兴趣的:(数据结构与算法,Java学习)