【数据结构】克鲁斯卡尔(Kruskal)算法 —PK— 普里姆(Prim)算法

简介: 【数据结构】克鲁斯卡尔(Kruskal)算法 —PK— 普里姆(Prim)算法

一、克鲁斯卡尔(Kruskal)算法


1)概述


先构造一个只含n个顶点的子图SG,然后从权值最小的边开始,若它的添加不使SG中产生回路【不产生回路】,则在SG上加上这条边,如此重复,直至加上n-1条边为止。


2)算法分析


设图G=(V, E) 是一个具有n个顶点的连通无向图,T=(V, TE)是图G的最小生成树。


V是T的顶点集


TE是T的边集


构建最小生成树的步骤:


T的初始化状态 T = (V, 空 ) ,即最小生成树T是图G的生成零图。


将图G中的边按照权值从小到大的顺序排序


依次选取每条边,若选取的边未使生成树T形成回路,则加入TE中,否则舍弃。直至TE中包含n-1条边为止


6288edc61d614625bf8b709b092df85c.png


例:


b388e700427e4fa6bfaaf030dc640e82.png


3)性能分析


构建最小生成树时,尽可能选择权值最小的边,但并不是每一条权值最小的边都必然可选,有可能构成回路。


最小生成树不是唯一的,因为同一时候可能有多重选择。


算法的时间复杂度:O(elge) ,即克鲁斯卡尔算法的执行时间主要取决于图的边数。


该算法适用于针对==稀疏图==的操作。


二、普里姆(Prim)算法


1)概述

取图中任意一个顶点v作为生成树的根,之后往生成树上添加新的顶点w。


在添加顶点w和已经在生成树上的顶点v之间必定存在一条边,并且该边的权值在所有连通顶点v和w之间的边中取值最小。


之后继续往生成树上添加顶点,直至生成树上含有n-1个顶点为止。


2)算法分析


例:从a顶点出发


6bb92b6f79c445cc9f93cdd1919f6e40.png


补充概念:


两个顶点之间的距离:指将顶点邻接到的关联边的权值


记为:|u,v|


顶点到顶点集合之间的距离:指顶点到顶点集合中所有顶点之间的距离中的最小值。


记为:|u, V| = min |u,v|


两个顶点集合之间的距离:指顶点集合到顶点集合中所有顶点之间的距离中的最小值。


记为:|U, V| = min |u, V|


de9ff5f8f4b741578ac77df0a72dd14c.png


3)步骤分析


在生成树的构造过程中,图中n个顶点分属两个集合:已落在生成树上的顶点集合U 和 尚未落在生成树上的顶级集合V-U,则应在所有连通U中顶点和V-U中的顶点的边中选取权值最小的边。


f0c835dab6484bf98693ac760d45b72e.png


4)代码实现


程序最后运行结果:


e83725d51d954befab9ff39c14238f1d.png


辅助数组:


4e4e853b845949bdbde04c5a3c27dc7c.png


算法:

public class MiniSpanTree_PRIM {
  // 内部类辅助记录从顶点U到V-U的代价最小的边
  private class CloseEdge {
    Object adjVex;
    int lowCost;
    public CloseEdge(Object adjVex, int lowCost) {
      this.adjVex = adjVex;   //顶点
      this.lowCost = lowCost;   //两个顶点之间最下的权值,
    }
  }
  // 用普里姆算法从第u个顶点出发构造网G的最小生成树T,返回由生成树边组成的二维数组
  public Object[][] PRIM(MGraph G, Object u) throws Exception {
        // 用于记录最小生成树的顶点,例如:tree[0][0]="v0",tree[0][1]="v2"
    Object[][] tree = new Object[G.getVexNum() - 1][2];
    int count = 0;  
        // 初始化数据
    CloseEdge[] closeEdge = new CloseEdge[G.getVexNum()];
    int k = G.locateVex(u);           //当前节点在
    for (int j = 0; j < G.getVexNum(); j++)   // 辅助数组初始化
      if (j != k)
        closeEdge[j] = new CloseEdge(u, G.getArcs()[k][j]);
    // 当最小权值为0时,表示当前节点已经在树中
    closeEdge[k] = new CloseEdge(u, 0);     // 初始,U={u}
    for (int i = 1; i < G.getVexNum(); i++) { // 选择其余G.vexnum - 1个顶点
      k = getMinMum(closeEdge);       // 求出T的下一个结点:第k个顶点
      tree[count][0] = closeEdge[k].adjVex; // 生成树的边放入数组
      tree[count][1] = G.getVexs()[k];    //
      count++;
      closeEdge[k].lowCost = 0;       // 第k个顶点并入U集
      for (int j = 0; j < G.getVexNum(); j++) //新顶点并入U后重新选择最小边
        if (G.getArcs()[k][j] < closeEdge[j].lowCost)
          closeEdge[j] = new CloseEdge(G.getVex(k), G.getArcs()[k][j]);
    }
    return tree;
  }
  //在closeEdge中选出lowCost最小且不为0的顶点
  private int getMinMum(CloseEdge[] closeEdge) {
    int min = Integer.MAX_VALUE;
    int v = -1;
    for (int i = 0; i < closeEdge.length; i++)
      if (closeEdge[i].lowCost != 0 && closeEdge[i].lowCost < min){
        min = closeEdge[i].lowCost;
        v = i;
      }
    return v;
  }
}

测试类:

public class Example6_4 {
  public final static int INFINITY = Integer.MAX_VALUE;
  public static void main(String[] args) throws Exception {
    Object vexs[] = { "v0", "v1", "v2", "v3", "v4", "v5" };
        // 各顶点之间边的关系
    int[][] arcs = { { 0, 7, 1, 5, INFINITY, INFINITY },
        { 7, 0, 6, INFINITY, 3, INFINITY }, 
                { 1, 6, 0, 7, 6, 4 },
        { 5, INFINITY, 7, 0, INFINITY, 2 },
        { INFINITY, 3, 6, INFINITY, 0, 7 },
        { INFINITY, INFINITY, 4, 2, 7, 0 } };
    MGraph G = new MGraph(GraphKind.UDG, 6, 10, vexs, arcs);
    Object[][] T = new MiniSpanTree_PRIM().PRIM(G, "v1");
    for (int i = 0; i < T.length; i++)
      System.out.println(T[i][0] + " - " + T[i][1]);
  }
}
// 开始顶点v1 调试结果:
// v1 - v4
// v1 - v2
// v2 - v0
// v2 - v5
// v5 - v3
// 开始顶点v0 调试结果:
//v0 - v2
//v2 - v5
//v5 - v3
//v2 - v1
//v1 - v4

5)性能分析

  • 普利姆算法的时间复杂度为:O(n2),执行时间主要取决于图的顶点数,与边数无关。
  • 该算法适用于==稠密图==的操作。


三、两个算法对比

image.png

相关文章
|
3月前
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
192 6
|
4月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
125 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
14天前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
76 29
|
14天前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
71 25
|
14天前
|
存储 人工智能 算法
C 408—《数据结构》算法题基础篇—数组(通俗易懂)
408考研——《数据结构》算法题基础篇之数组。(408算法题的入门)
58 23
|
1月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
49 2
|
2月前
|
存储 运维 监控
探索局域网电脑监控软件:Python算法与数据结构的巧妙结合
在数字化时代,局域网电脑监控软件成为企业管理和IT运维的重要工具,确保数据安全和网络稳定。本文探讨其背后的关键技术——Python中的算法与数据结构,如字典用于高效存储设备信息,以及数据收集、异常检测和聚合算法提升监控效率。通过Python代码示例,展示了如何实现基本监控功能,帮助读者理解其工作原理并激发技术兴趣。
68 20
|
3月前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
|
3月前
|
算法
数据结构之路由表查找算法(深度优先搜索和宽度优先搜索)
在网络通信中,路由表用于指导数据包的传输路径。本文介绍了两种常用的路由表查找算法——深度优先算法(DFS)和宽度优先算法(BFS)。DFS使用栈实现,适合路径问题;BFS使用队列,保证找到最短路径。两者均能有效查找路由信息,但适用场景不同,需根据具体需求选择。文中还提供了这两种算法的核心代码及测试结果,验证了算法的有效性。
143 23
|
3月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
99 1