克鲁斯卡尔(Kruskal)算法求最小生成树

  • 算法思想:贪心算法,先将图的所有点存起来,然后每次找出该图中权最小的边,如果该边加入到已经生成的树中不会形成回路就可以加入,否则不行,直到边数等于顶点数减一时停止加边进去

  • 下图是kruskal算法的图解

  • 克鲁斯卡尔(Kruskal)算法求最小生成树_第1张图片

  • 上代码,注意要判断是否形成回路,这是该算法的核心

    /*
     * 类描述:克鲁斯卡尔算法求最小生成树
     * @author Lqx
     */
    public class Kruskal {
    	public static final int M = -1;
    	// 建图(用二维矩阵存储图)
    	static int[][] map = { 
    			{ M, 9, M, M, 16, 2 }, 
    			{ 9, M, 14, M, M, 2 }, 
    			{ M, 14, M, 7, M, 21 },
    			{ M,  M, 7, M, 5, 3 },
    			{ 16, M, M, 5, M, 7 }, 
    			{ 2, 2, 21, 3, 7, M } 
    			};
    	static int[][] tree = new int[map.length][map.length]; //存放最小生成树
    	/*
    	 * 方法描述:该方法用于求最小生成树
    	 * @param a:待求的图
         * @author Lqx
    	 */
    	static int[][] kruskal(int[][] a) {
    
    		int vexnumber = a.length;
    		int begin = 0; // 存放起点下标
    		int tempmin = -1; //暂时存放最小边
    		int end = -1; //存放树枝端点
    		int number = 0; //计算边数是否到了
    		for (int i = 0; i < tree.length; i++) {
    			for (int j = 0; j < tree.length; j++) {
    				tree[i][j] = -1; // 初始化,-1对后面判断有用
    			}
    		}
    		while (number != vexnumber - 1) {
    			// 只要边数等于顶点数-1就结束,树的要求:边数=顶点数-1
    			for (int i = 0; i < vexnumber; i++) {
    
    				for (int j = i + 1; j < vexnumber; j++) {
    					if (a[i][j] != M) {
    						// 必须是存在通路
    						if (tempmin == -1 || a[i][j] < tempmin) {
    							// 找最小边
    							tempmin = a[i][j]; // 暂时存放最小边
    							begin = i;
    							end = j;
    						}
    					}
    				}
    			}
    			tempmin = -1; //恢复最小值
    			if (tree[begin][end] == -1) {
    				if (searchparent(tree, begin, end)) {
    					// 如果要加入的边的两个端点在树中有一个共同的邻点那就是会形成回路
    
    					tree[begin][end] = a[begin][end];
    					// 不会形成回路的边加入
    					a[begin][end] = -1; // 加入后让原本图中的边变成无效
    				}
    			}
    			number++; // 计算树枝的数量(边数)
    		}
    		return tree;
    
    	}
    	/*
    	 * 方法描述:该方法用来判断要加入的边是否存在回路
    	 * @param tree:现已经生成的树   begin:待判断边的其中一个端点   end:待判断的边的另一个端点
    	 * @return true:不存在回路,可以加入该边    false:存在回路,不可加入该边
    	 */
    	private static boolean searchparent(int[][] tree, int begin, int end) {
    
    		boolean isok = true;
    		for (int j = 0; j < tree.length; j++) {
    			if (tree[begin][j] != -1 && tree[end][j] != -1) {
    				// 存在终点相同的路径说明他们存在一个共同的邻点,会形成回路
    				isok = false;
    			}
    		}
    
    		return isok;
    	}
    
    	public static void main(String[] args) {
    		int[][] b = kruskal(map);
    		System.out.println("该图的最小生成树结点和树枝情况如下:");
    		for (int i = 0; i < b.length; i++) {
    			for (int j = 0; j < b.length; j++) {
    				if (b[i][j] != -1) {
    					System.out.println( "v"+(i+1) + "-->v"+(j+1) + ": " + b[i][j] + "(权值)");
    				}
    			}
    		}
    	}
    
    }
    

    结果如下(输出记过并不是按照最小生成树的生成过程输出的,而是按照二维矩阵的遍历输出):

  • 克鲁斯卡尔(Kruskal)算法求最小生成树_第2张图片

你可能感兴趣的:(graph,java,kruskal,最小生成树,克鲁斯卡尔算法)