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

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

  • 下图是kruskal算法的图解

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

    /*
     * 类描述:克鲁斯卡尔算法求最小生成树
     * @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] + "(权值)");
    				}
    			}
    		}
    	}
    
    }
    

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

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值