1.贪心算法思想

贪心算法的基本思想是找出整体当中每个小的局部的最优解,并且将所有的这些局部最优解合起来形成整体上的一个最优解。因此能够使用贪心算法的问题必须满足下面的两个性质:

  • 1.整体的最优解可以通过局部的最优解来求出;
  • 2.一个整体能够被分为多个局部,并且这些局部都能够求出最优解。

2.贪心算法的基本策略 :

1、从问题的某个初始解出发。
2、采用循环语句,当可以向求解目标前进一步时,就根据局部最优策略,得到一个部分解,缩小问题的范围或规模。
3、将所有部分解综合起来,得到问题的最终解。

(2-1)Kruskal算法

  • 将所有边按照权值的大小进行升序排序,然后从小到大一一判断,条件为:如果这个边不会与之前选择的所有边组成回路,就可以作为最小生成树的一部分;反之,舍去。直到具有 n 个顶点的连通网筛选出来 n-1 条边为止。筛选出来的边和所有的顶点构成此连通网的最小生成树。

(2-2)Prim算法

  • Prim算法从任意一个顶点开始,每次选择一个与当前顶点集最近的一个顶点,并将两顶点之间的边加入到树中。

3.数据结构
Prim算法:

  • a. 在一个加权连通图中,顶点集合V,边集合为E
  • b. 任意选出一个点作为初始顶点,标记为visit,计算所有与之相连接的点的距离,选择距离最短的,标记visit.
  • c. 重复以下操作,直到所有点都被标记为visit:
    在剩下的点钟,计算与已标记visit点距离最小的点,标记visit,证明加入了最小生成树。

Kruskal算法

  • a.假定拓扑图的边的集合是E,初始化最小生成树边集合G={}。
  • b. 遍历集合E中的所有元素,并且按照权值的大小进行排序。
  • c. 找出E中权值最小的边e 。
  • d .如果边e不和最小生成树集合G中的边构成环路,则将边e加到边集合G中;否则测试下一条权值次小的边,直到满足条件为止。
  • e. 重复步骤b,直到G=E。

4.数据模型

5.程序代码
Kruskal算法Java代码实现

public class Kruskal {public int edgeNums;                           //边的数量public char[] data;                             //存储结点public int[][] matrix;                          //邻接矩阵存储权重private static final int INF = Integer.MAX_VALUE; //表示结点不通public Kruskal(char[] data, int[][] matrix) {int length = data.length;this.data = new char[length];this.matrix = new int[length][length];for (int i = 0; i < length; i++) {this.data[i] = data[i];}for (int s = 0; s < length; s++) {for (int k = 0; k < length; k++) {this.matrix[s][k] = matrix[s][k];}}for (int m = 0; m < length; m++) {for (int n = m + 1; n < length; n++) {if (matrix[m][n] != INF) {this.edgeNums++;}}}}/*** 将遍历邻接矩阵将边加入到Edge数组中** @return Edge数组*/public Edge[] getEdges() {int length = this.data.length;int index = 0;Edge[] edges = new Edge[this.edgeNums];for (int m = 0; m < length; m++) {for (int n = m + 1; n < length; n++) {if (matrix[m][n] != INF) {edges[index] = new Edge(data[m], data[n], matrix[m][n]);index++;}}}return edges;}/*** 对Edge数组进行排序** @param edges 数组引用*/public void sortEdges(Edge[] edges) {for (int k = 0; k < edges.length - 1; k++) {for (int s = 0; s < edges.length - k - 1; s++) {if (edges[s].weight > edges[s + 1].weight) {Edge temp = edges[s];edges[s] = edges[s + 1];edges[s + 1] = temp;}}}}/*** 克鲁斯卡尔核心方法* 流程:* 1.将图中的边放到集合中* 2.边排序   - 》 权重  T集合* 3.对T集合进行遍历* T*/public void kruskal() {Edge[] edges = getEdges();sortEdges(edges);Edge[] result = new Edge[edgeNums];int[] ends = new int[edgeNums];int index = 0;for (int k = 0; k < edgeNums; k++) {int front = getPosition(edges[k].front);int after = getPosition(edges[k].after);int m = getEnd(ends, front);int n = getEnd(ends, after);if (m != n) {ends[m] = n;result[index++] = edges[k];}}System.out.println(Arrays.toString(result));}/*** 得到末尾的结点** @param ends 存储* @param k    元素下标* @return 返回元素*/public int getEnd(int[] ends, int k) {while (ends[k] != 0) {k = ends[k];}return k;}/*** 获取元素对于的下标** @param ch 待查询字符* @return 下标*/private int getPosition(char ch) {for (int i = 0; i < data.length; i++) {if (data[i] == ch) {return i;}}return -1;}public void printMatrix() {System.out.println("二维矩阵列表为:");for (int[] cur : matrix) {System.out.println(Arrays.toString(cur));}System.out.println("边的大小为:" + this.edgeNums);}/ /main测试public static void main(String[] args) {char[] vertex = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};int[][] matrix = {{0, 12, INF, INF, INF, 16, 14},{12, 9, 10, INF, INF, 7, INF},{INF, 10, 0, 3, 5, 6, INF},{INF, INF, 3, 0, 4, INF, INF},{INF, INF, 5, 4, 0, 2, 8},{16, 7, 6, INF, 2, 0, 9},{14, INF, INF, INF, 8, 9, 0}};Kruskal kruskal = new Kruskal(vertex, matrix);kruskal.printMatrix();kruskal.kruskal();}
}class Edge {public char front;public char after;public int weight;public Edge(char front, char after, int weight) {this.front = front;this.after = after;this.weight = weight;}@Overridepublic String toString() {return "Edge{" +"front=" + front +", after=" + after +", weight=" + weight +'}';}
}Prim算法Java代码实现
public class Prim {public static void main(String[] args) {char[] data = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};int nodes = data.length;int[][] weight = {{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},};MinTree minTree = new MinTree();Graph graph = new Graph(nodes);minTree.createGraph(nodes, data, weight, graph);minTree.showGraph(graph);minTree.prim(graph, 0);}
}class MinTree {/*** 初始化无向图* @param nodes 结点数* @param data  结点数组* @param weight 权重邻接矩阵* @param graph  无向图*/public void createGraph(int nodes, char[] data, int[][] weight, Graph graph) {int i, j;for (i = 0; i < nodes; i++) {graph.data[i] = data[i];for (j = 0; j < nodes; j++) {graph.weight[i][j] = weight[i][j];}}}/*** 最小生成树问题* 1.给定一个无向连通图,如果选取生成一棵树,使得树上所有的权总和最小,这就是最小生成树* 2.给定n个结点,一定有n-1条边* 两种算法 1.普里姆算法  和  克鲁斯卡尔算法* @param graph  邻接图* @param v      开始结点的下标**  1.创建V集合保存结点    ---  遍历*  2.从某个结点出发, 每次取出 A  E  T*/public void prim(Graph graph, int v) {int x1 = -1, x2 = -1;int nodeNums = graph.nodes;int[] visited = new int[nodeNums];visited[v] = 1;int minWeight = 10000;               //先自定义最大权重,后面替换for (int k = 1; k < nodeNums; k++) {    //n个结点需要n-1条边for (int al = 0; al < nodeNums; al++) {    //已经标记的for (int not = 0; not < nodeNums; not++) {  //未标记的if (visited[al] == 1 && visited[not] == 0 && graph.weight[al][not] < minWeight) {minWeight = graph.weight[al][not];x1 = al;x2 = not;}}}visited[x2] = 1;minWeight = 10000;System.out.println("边<"+graph.data[x1]+"-"+graph.data[x2]+">"+"权值为:"+graph.weight[x1][x2]);}}//显示邻接矩阵public void showGraph(Graph graph) {for (int[] cur : graph.weight) {System.out.println(Arrays.toString(cur));}}
}class Graph {protected int nodes;          //结点的个数protected char[] data;         //结点的数据protected int[][] weight;     //结点的邻接矩阵public Graph(int nodes) {this.nodes = nodes;data = new char[nodes];weight = new int[nodes][nodes];}
}

6.测试
(1)Kruskal算法测试数据如下

(其中的INF表示两顶点之间不通)

控制台结果如下:

(2)Prim算法测试数据如下:

(1000表示两个顶点不连通,也可也和上面的Kruskal算法一样使用int的最大值65535表示)
控制台结果如下:

7.结果分析:
Prim
通过邻接矩阵图表示的简易实现中,找到所有最小权边共需O(V)的运行时间。使用简单的二叉堆与邻接表来表示的话,普里姆算法的运行时间则可缩减为O(ElogV),其中E为连通图的边数,V为顶点数。如果使用较为复杂的斐波那契堆,则可将运行时间进一步缩短为O(E+VlogV),这在连通图足够密集时,可较显著地提高运行速度

Kruskal
克鲁斯卡尔算法的时间复杂度主要由排序方法决定,而克鲁斯卡尔算法的排序方法只与网中边的条数有关,而与网中顶点的个数无关,当使用时间复杂度为O(elog2e)的排序方法时,克鲁斯卡尔算法的时间复杂度即为O(log2e),因此当网的顶点个数较多、而边的条数较少时,使用克鲁斯卡尔算法构造最小生成树效果较好

实验1 最小生成树问题【Kruskal+Prim】相关推荐

  1. 【数据结构笔记29】最小生成树问题:Prim算法与Kruskal算法

    本次笔记内容: 8.1.1 Prim算法 8.1.2 Kruskal算法 文章目录 最小生成树问题 什么是最小生成树(Minimum Spanning Tree) 贪心算法 Prim算法 Kruska ...

  2. 【数据结构】最小生成树问题(Prim算法和Kruskal算法)

    相关概念 连通图与它的生成树 连通图的生成树是包含图中全部顶点的一个极小连通子图.若图的顶点数为n,则它的生成树含有n-1条边.一个连通图可能拥有多个生成树. 最小生成树(Minimum-Spanni ...

  3. HDU 1879(最小生成树问题,Prim)

    Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).现得到城镇道路统计 ...

  4. 【算法】Kruskal算法(解决最小生成树问题) 含代码实现

    Kruskal算法和Prim算法一样,都是求最小生成树问题的流行算法. 算法思想: Kruskal算法按照边的权值的顺序从小到大查看一遍,如果不产生圈或者重边,就把当前这条边加入到生成树中. 算法的正 ...

  5. 最小生成树 kruskal_使用Kruskal算法求解Java最小生成树问题

    最小生成树 kruskal In Electronic Circuit we often required less wiring to connect pins together. We can m ...

  6. 数据结构与算法-Prim算法解析与解决修路最小生成树问题

    文章目录 简介 Prim算法 最小生成树 应用场景 问题描述 思路分析 代码实现 简介 Prim算法 ​ 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索 ...

  7. Python小白的数学建模课-18.最小生成树问题

    Python小白的数学建模课-18.最小生成树问题 最小生成树(MST)是图论中的基本问题,具有广泛的实际应用,在数学建模中也经常出现. 路线设计.道路规划.官网布局.公交路线.网络设计,都可以转化为 ...

  8. 最小生成树问题的算法笔记

    最小生成树问题 前提 在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集且为无循环图,使得 ...

  9. 使用贪心算法解决最小生成树问题。

    使用贪心算法解决最小生成树问题. #include<iostream> #include<algorithm> using namespace std; const int M ...

最新文章

  1. foxmail提示不知道这样的主机_不知道和婚礼策划师沟通时谈哪些?这样做让你高效备婚...
  2. JavaWeb(五)——Servlet、Mapping问题、ServletContext
  3. 9-18 学习如何使用Python包的管理
  4. 阿里开发者们的第15个感悟:做一款优秀大数据引擎,要找准重点解决的业务场景
  5. 硬核科普!携号转网的技术原理分析!
  6. 错误处理和调试2 - C++快速入门31
  7. Await Async和Thread.waitAll想法?未完待续
  8. 科大讯飞语音识别demo
  9. django基础入门(3)django中模板
  10. php smarty程序设计,Smarty程序设计-动态文件操作
  11. SpringBoot整合ureport2
  12. SQL保姆级教程来了,0基础怎么快速上手sql?面试官会从哪些方面考sql?(看完你就能5天掌握SQL要点)...
  13. 用Xposed框架拦截微信、人人、QQ等LBS应用的当前位置
  14. 0xE06D7363: Microsoft C++ Exception.
  15. ThinkPad E450 最新macOS BigSur黑苹果安装教程(OpenCore引导)
  16. 傅里叶变换及其应用笔记(part 1)
  17. 云智信短信验证码php示例
  18. 做人,该善良时就善良,该勇敢时就要有勇气去对应
  19. 拉普拉斯算子——matlab
  20. 那些可以加速国内外开源库的免费CDN

热门文章

  1. JS高级程序设置笔记(二)
  2. Qt学习之路(1)------Qt常用类用法说明
  3. .NET源码反编译和加密
  4. python整数和浮点数相乘_python中整数除法和浮点数到整数转换之间的区别是什么原因?...
  5. pandas删除满足条件的行_入门Pandas练习
  6. 群晖218J安装mysql_ds216(群晖218j可以换内存吗)
  7. c语言如何定义比较大的数组_C语言:数据结构-数组的定义、逻辑结构和特点
  8. 七十一、Python | Leetcode字符串系列(上篇)
  9. 工程制图 (组合体的视图与尺寸注法)
  10. EPERM: operation not permitted, mkdir 'C:\Program Files\nodejs'