普利姆算法生成最小生成树

20 篇文章 0 订阅
17 篇文章 1 订阅
  • 举个最小生成树的例子:
    在一个地区有很多个小村庄,并且每个村之间都可以修路进行连通。实际上,每条路由于地形不一样,所需的经费不同,并且不可能每两个村庄都直接互通,可以间接互通,从而降低经费。如何实现呢?这时候最小生成树的作用就体现出来了。
  • 如下图:(每个点代表一个村庄,边上的值代表修路所需经费)
    在这里插入图片描述
    生成最小生成树的方法最经典的有两种:普利姆算法克鲁斯卡尔算法 。下面我们来说说普利姆算法,普利姆算法又叫加点法。
  • 通过普利姆算法最小生成树的要点主要简单归纳为如下三点:
    1)任意选择一个点作为起点
    2) 在未连接的点集中选择与已连接部分的路径最短的点
    3)不能形成封闭回路
以C为起点为例:

1)找到C点
在这里插入图片描述
2)在未连接的点集中选择与已连接部分(C点)的路径最短的点:可以看出是G点,将他们连接起来。在这里插入图片描述
3)继续第二步,直到将所有点直接或者连通在一起:在未连接的点集中选择与已连接部分(C, G点)的路径最短的点:可以看出是G点,将他们连接起来。可以看出是B点,将他们连接起来。
在这里插入图片描述
以此进行下去 最后结果如下:也就是最小生成树了。
在这里插入图片描述
上面就是普利姆算法的基本思路。如何用代码实现呢,往下看。

  • 代码实现

    要记录一个图,我们在代码中就要记录点还有点之间的边,所有我们需要一个点集和一个边集
    点集我们可以通过一个Set集合来充当
    边集合我们可以通过一个二维数组来建立: 如下图,表示点与点之间的距离,数组的索引对应MapNode中的index值。
    在这里插入图片描述
  • 封装一个图中所需的点

public class MapNode {
    public String val;
    public List<MapNode> neighbor;//用来记录最终点周围的连接情况
    public int index;//用于绑定图中的边集

    public MapNode(String val, int index) {
        this.val = val;
        this.index = index;
        neighbor = new ArrayList<>();
    }
}
  • 普利姆算法的核心代码
//普利姆算法
	public static void prim(Set<MapNode> pointSet, int[][] distance, MapNode startPoint){
	        Set<MapNode> rs = new HashSet<>();
	        rs.add(startPoint);
	        while (rs.size() < pointSet.size()){
	            getMinDis(pointSet,distance,rs);
	        }
	    }
    
  //找到距离已有的点最近的点
    public static void getMinDis(Set<MapNode> pointSet, int[][] distance, Set<MapNode> rs){
        MapNode start = null;
        MapNode end = null;
        int minDis = Integer.MAX_VALUE;
        for(MapNode temp : rs){
            int idx = temp.index;
            for(int i = 0; i < distance[temp.index].length; i ++){//根据当前点索引到边的二维数组中找到该点到每个点的距离的一个一维数组,进行判断
                if(distance[idx][i] < minDis  //找到距离最近的点
                        && i != idx //当前点无需在自己比较距离
                        && !rs.contains(getMapNodeByInx(pointSet,i))
                ){
                    start = temp;
                    end = getMapNodeByInx(pointSet,i);
                    minDis = distance[idx][i];
                }
            }
        }
        //将距离最短的两个点连接在一起
        start.neighbor.add(end);
        end.neighbor.add(start);
        System.out.println(start.val+"----->"+end.val);
        rs.add(end);
    }
    
	//根据索引找到相应的点
	public static MapNode getMapNodeByInx(Set<MapNode> pointSet, int index){
       		 for(MapNode node : pointSet)if (node.index == index) return node;
        	 return null;
    }
    
  • 记录上面所举例的图并且通过普利姆算法最终生成最小生成树
public class Main {
    public static void main(String[] args) {
        //将图中的点构建出来
        MapNode pointA = new MapNode("A",0);
        MapNode pointB = new MapNode("B",1);
        MapNode pointC = new MapNode("C",2);
        MapNode pointD = new MapNode("D",3);
        MapNode pointE = new MapNode("E",4);
        MapNode pointF = new MapNode("F",5);
        MapNode pointG = new MapNode("G",6);

        int max = Integer.MAX_VALUE;
        //图中每个点到图中点的距离(每条边的权值)//边集合
        int[][] distance = new int[][]{
                {0,5,max,13,max,max,8},
                {5,0,6,max,max,max,10},
                {max,6,0,max,max,8,4},
                {13,max,max,0,9,max,11},
                {max,max,max,9,0,9,7},
                {max,max,8,max,9,0,20},
                {8,10,4,11,7,20,0}
        };
		//点集
        Set<MapNode> pointSet = new HashSet<>();
        pointSet.add(pointA);
        pointSet.add(pointB);
        pointSet.add(pointC);
        pointSet.add(pointD);
        pointSet.add(pointE);
        pointSet.add(pointF);
        pointSet.add(pointG);

        prim(pointSet,distance,pointC);//执行之后就可以查看生成的结果了
		System.out.println("生成完毕")// debug一下
    }

  • 生成结果:
    在这里插入图片描述
    暂且不全部展开,可以看到,和我们上面生成的最小生成树结果是一样的。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
普利算法是一种用于求解无向图的最小生成树的基本算法。它以一个起始节点开始,每次将一个未被访问的节点加入到最小生成树集合中,并选择与该集合相邻的边中权重最小的边和它连接的未访问节点,直到最小生成树集合包含了图中的所有节点。普利算法的时间复杂度为O(n^2)。 以下是普利算法的步骤: 1. 选择一个起始节点作为最小生成树的起点。 2. 将该起始节点加入最小生成树集合,并将其标记为已访问。 3. 在所有与最小生成树集合相邻的边中,选择权重最小的边和它连接的未访问节点。 4. 将该边和节点加入最小生成树集合,并将该节点标记为已访问。 5. 重复步骤3和步骤4,直到最小生成树集合包含了图中的所有节点。 以下是Python实现普利算法的代码: ```python def prim(graph): # 选择一个起始节点作为最小生成树的起点 start_node = list(graph.keys())[0] # 将该起始节点加入最小生成树集合,并将其标记为已访问 visited = [start_node] # 初始化最小生成树的权重为0 min_weight = 0 # 初始化最小生成树的边为空 min_tree = [] # 重复步骤3和步骤4,直到最小生成树集合包含了图中的所有节点 while len(visited) < len(graph): # 在所有与最小生成树集合相邻的边中,选择权重最小的边和它连接的未访问节点 min_edge = None for node in visited: for neighbor, weight in graph[node].items(): if neighbor not in visited: if min_edge is None or weight < min_edge[2]: min_edge = (node, neighbor, weight) # 将该边和节点加入最小生成树集合,并将该节点标记为已访问 visited.append(min_edge[1]) min_weight += min_edge[2] min_tree.append(min_edge) # 返回最小生成树的权重和边 return min_weight, min_tree ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值