文章目录

  • 一、概念
  • 二、算法
    • 2.1 Prim算法
    • 2.2 Kruskal算法

笔记来源:中国大学MOOC王道考研

一、概念

  • 连通图:图中任意两点都是连通的,那么图被称作连通图

  • 生成树:连通图包含全部顶点的一个极小连通子图

  • 最小生成树:在含有n个顶点的带权无向连通图中选择n-1条边,构成一棵极小连通子图,并使该连通子图中n-1条边上权值之和达到最小,则称其为连通网的最小生成树(不一定唯一)。

    • 性质1:不一定唯一
    • 性质2:如果所有边的权重都不相同,则一定唯一
    • 性质3:如果连通图只有n-1条边,则最小生成树就是它本身
    • 性质4:最小生成树的边数为n-1

二、算法

2.1 Prim算法

步骤如下:

  1. 初始化,取任意顶点加入结果树:

  2. 加入A相邻的且不在结果树中,并且是最小权值的点C

  3. 加入与A,C相邻的且不在结果树中,并且是最小权值的点B(BC最小)

  4. 重复上述步骤,直到所有顶点都进入结果树:

java代码实现如下:

我们需要用两个数组来实现过程:

  • min_weight[n]:当前结果树到所有顶点的最短距离
  • adjvex[n]:adjvex[C]=0,代表C是通过A加入结果树的(0是A的下标)

  /** 首先我们给出图的存储结构*/
package MST;import java.util.List;public class Graph {/** 点的存储*/private List<String> vex;/** 边的存储*/private int edges[][];public Graph(List<String> vex, int[][] edges) {this.vex = vex;this.edges = edges;}public List<String> getVex() {return vex;}public void setVex(List<String> vex) {this.vex = vex;}public int[][] getEdges() {return edges;}public void setEdges(int edges[][]) {this.edges = edges;}public int getVexNum() {return vex.size();}public int getEdgeNum() {return edges.length;}
}

然后初始化图:

public class Prime {int m = Integer.MAX_VALUE;int[][] edges = {{0, 3, 1, m, 4},{3, 0, 2, m, m},{1, 2, 0, 5, 6},{m, m, 5, 0, m},{4, m, 6, m, 0},};//打印最小生成树void MST_Prime(Graph G) {int vexNum = G.getVexNum();//节点个数int[] min_weight = new int[vexNum];//当前结果树到所有顶点的最短距离int[] adjvex = new int[vexNum];//adjvex[C]=0,代表C是通过A加入结果树的(0是A的下标)/*初始化两个辅助数组*/for(int i = 0; i < vexNum; i++) {min_weight[i] = (G.getEdges())[0][i];//第一个顶点到其余顶点的距离adjvex[i]=0;}int min_edg;//当前挑选的最小权值int min_vex = 0;//最小权值对应的节点下标/*循环剩余n-1个点*/for(int i = 1; i < vexNum; i++) {min_edg = Integer.MAX_VALUE;for(int j = 1; j < vexNum; j++) {if(min_weight[j]!=0 && min_weight[j] < min_edg) {//寻找还没有被挑选进来的,最小权重的点min_edg = min_weight[j];min_vex = j;                  }}min_weight[min_vex] = 0;//纳入结果树          /*修改对应辅助数组的值*/for(int j = 0; j < vexNum; j++) {if(min_weight[j]!=0 && (G.getEdges())[min_vex][j]<min_weight[j] && (G.getEdges())[min_vex][j]>0) {min_weight[j] = (G.getEdges())[min_vex][j];adjvex[j]=min_vex;}}int pre = adjvex[min_vex];int end = min_vex;System.out.println("("+G.getVex().get(pre)+","+G.getVex().get(end)+")");}}//初始化图Graph init() {List<String> vex=new ArrayList<String>();vex.add("A");vex.add("B");vex.add("C");vex.add("D");vex.add("E");Graph graph = new Graph(vex, edges);return graph;}public static void main(String[] args) {Prime prime = new Prime();Graph graph = prime.init();prime.MST_Prime(graph);}
}

打印结果如下:

(A,C)
(C,B)
(A,E)
(C,D)

2.2 Kruskal算法

步骤如下:

  1. 每个顶点都是独立的树

  2. 挑选最短的边AC,加入边集中

  3. 依次加入BC,AB,但是AB构成了回路,舍弃

  4. 重复直到取了n-1条边

java代码实现如下:

使用 并查集堆排序kruskal算法

引用并查集博客:Java实现并查集

//首先我们实现并查集(用来判断是否构成回路--是否属于一个并查集)
public class UnionFindSet {//查询树的根public static int find(int x, int [] par){if(par[x] == x){return x;}else{//压缩路径,第二次查询可以直接返回x的根而不用递归return par[x] = find(par[x], par);}}//合并public static void unite(int x, int y, int [] par, int [] rank){x = find(x, par);y = find(y, par);if(x == y){return ;}if(rank[x] < rank[y]){par[x] = y;}else{par[y] = x;if(rank[x] == rank[y]) rank[x]++;}}//判断x和y是否属于同一个集合public static boolean same(int x, int y, int [] par){return find(x, par) == find(y, par);}
}

然后实现堆排序(稍作修改):

堆排序参考这篇博客:Java实现堆排序和图解

public class HeapSort {public static void sort(Edge[] arr){//1.构建大顶堆for(int i=arr.length/2-1;i>=0;i--){//从第一个非叶子结点从下至上,从右至左调整结构adjustHeap(arr,i,arr.length);}//2.调整堆结构+交换堆顶元素与末尾元素for(int j=arr.length-1;j>0;j--){swap(arr,0,j);//将堆顶元素与末尾元素进行交换adjustHeap(arr,0,j);//重新对堆进行调整}}/*** 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)* @param arr* @param i* @param length*/public static void adjustHeap(Edge[] arr,int i,int length){Edge temp = arr[i];//先取出当前元素ifor(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始if(k+1<length && arr[k].weight<arr[k+1].weight){//如果左子结点小于右子结点,k指向右子结点k++;}if(arr[k].weight >temp.weight){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)arr[i] = arr[k];i = k;}else{break;}}arr[i] = temp;//将temp值放到最终的位置}/*** 交换元素* @param arr* @param a* @param b*/public static void swap(Edge[] arr,int a ,int b){Edge temp=arr[a];arr[a] = arr[b];arr[b] = temp;}
}

最后我们实现Kruskal算法:

package MST;import java.util.ArrayList;
import java.util.List;public class Kruskal {int m = Integer.MAX_VALUE;int[][] arr = {{0, 3, 1, m, 4},{3, 0, 2, m, m},{1, 2, 0, 5, 6},{m, m, 5, 0, m},{4, m, 6, m, 0},};Graph init() {List<String> vex=new ArrayList<String>();vex.add("A");vex.add("B");vex.add("C");vex.add("D");vex.add("E");Graph graph = new Graph(vex, arr);return graph;}//kruskal算法void MST_Kruskal(Graph G, Edge[] edges, int[] parents, int[] rank) {HeapSort.sort(edges);//堆排序for(int i = 0; i < G.getEdgeNum(); i++) {if(!UnionFindSet.same(edges[i].a, edges[i].b, parents)) {UnionFindSet.unite(edges[i].a, edges[i].b, parents, rank);System.out.println("("+G.getVex().get(edges[i].a)+","+G.getVex().get(edges[i].b)+")");}}}public static void main(String[] args) {Kruskal kruskal = new Kruskal();Graph graph = kruskal.init();int[] parents = {0,1,2,3,4};int[] rank = {1,1,1,1,1};Edge[] edges = new Edge[10];int index = 0;for(int i = 0; i < 5;i++) {for(int j=0;j<i;j++) {edges[index] = new Edge();edges[index].weight = kruskal.arr[i][j];edges[index].a = i;edges[index++].b = j;}}kruskal.MST_Kruskal(graph, edges, parents, rank);}
}

输出结构为:

(C,A)
(C,B)
(E,A)
(D,C)

最小生成树的java实现相关推荐

  1. 图的最小生成树(java实现)

    1.图的最小生成树(贪心算法) 我两个算法的输出都是数组表示的,当前的索引值和当前索引对应的数据就是通路,比如parent[2] = 5;即2和5之间有一个通路,第二个可能比较好理解,第一个有点混乱 ...

  2. Prim算法实现最小生成树(Java)

    最小生成树包含n个顶点和(n-1)条边,并且边的权重最小.Prim算法的思想是:由一颗小树慢慢长大,首先分为两个顶点集合,最小生成树的顶点集合A,和不在生成树中的顶点集合B,每次从B中找一个顶点v,使 ...

  3. Prim算法求图的最小生成树(Java)

    package Algorithm.prim;import java.util.Arrays;/*** 普利姆算法解决最小生成树问题 Prim算法的实现过程 首先以一个结点作为最小生成树的初始结点,然 ...

  4. java 最小生成树_图的最小生成树(java实现)

    1.图的最小生成树(贪心算法) 我两个算法的输出都是数组表示的,当前的索引值和当前索引对应的数据就是通路,比如parent[2] = 5;即2和5之间有一个通路,第二个可能比较好理解,第一个有点混乱 ...

  5. prim 最小生成树算法 java实现

    http://ac.jobdu.com/problem.php?pid=1024 import java.util.Arrays; import java.util.Scanner;public cl ...

  6. java贪心,java实现贪心算法

    并证明了贪心算法解决此问题的有效性,且进行了实例验证,并进 行了复杂度分析,此算法是解决资源组合规划问题较好的方法. 关键词:贪心算法;java 程序;复杂度分析;...... 数据结构与算法 实验名 ...

  7. Prim算法伪+代码讲解

    1.快速了解Prim算法 学过数据结构的看官老爷们都应该知道,普里姆太熟悉了,不就是最小生成树的算法嘛,是的它是一种求最小树的算法.本文通过剖析伪代码的过程来理解这个"easy algori ...

  8. prim算法(普里姆算法)详解

    prim算法(普里姆算法)详解 了解了什么是最小生成树后,本节为您讲解如何用普里姆(prim)算法查找连通网(带权的连通图)中的最小生成树. 普里姆算法查找最小生成树的过程,采用了贪心算法的思想.对于 ...

  9. 图的深度优先遍历和宽度优先遍历C语言,图的广度、深度优先遍历 C语言

    以下是老师作为数据结构课的作业的要求,没有什么实际用处和可以探讨和总结的的地方,所以简单代码直接展示. 宽度优先遍历: #include #include #include using namespa ...

最新文章

  1. Facebook开源高效图像Transformer,速度、准确率与泛化性能媲美SOTA CNN
  2. 51.1AP!单阶段检测器的新纪录,TOOD:即插即用的检测器换头术,显著提升性能
  3. 卫星导航系统脆弱性评估与对策
  4. Spark详解(五):Spark作业执行原理
  5. dxf转pdf linux,4个最好的PDF转DXF格式的在线转换器
  6. java写spark碰到输出为[Ljava.lang.String;@889a8a8的情况
  7. BFC的布局规则以及触发条件
  8. win8 开发之旅(5) --五子棋游戏开发
  9. 基于Edge插件+格式工厂下载B站上的喜欢视频
  10. 台式计算机怎么装,台式机声卡如何安装
  11. 大型即时通讯系统微信、陌陌架构分析全记录!
  12. 《拆掉思维里的墙》的读后感作文900字
  13. 炸裂了!来了一波新年微信红包封面,抓紧领取,先到先得!
  14. 2022眼视光展,护眼产品展,眼睛健康展,视力康复展
  15. 【汽车总线技术】CAN和CAN FD总线故障诊断
  16. 聊一下面试经常问的SQL注入
  17. Java基础知识学习笔记总结
  18. 累加器是寄存器吗?寄存器、累加器、暂存器有什么区别?
  19. 破解ChatGPT机遇与挑战,中国AIGC产业峰会给出最强答案
  20. “笨办法”学Python 3 ——练习 15 阅读文件

热门文章

  1. micropython入门教程-如何学习MicroPython MicroPython入门知识
  2. python骗局-python 无良培训忽悠骗局知多少?
  3. python编程100个小程序-用python编写一个闹钟小程序
  4. python自动化测试-五大自动化测试的Python框架
  5. 零基础学python知乎-35岁了零基础自学Python可行吗?
  6. python爬虫怎么赚钱-python爬虫怎么赚钱
  7. python从入门到精通-终于懂得python从入门到精通教程
  8. python能做什么工作-学完python能从事什么工作?
  9. 讯飞语音输入法免费版
  10. 叮当:一个开源的树莓派中文智能音箱项目