`
128kj
  • 浏览: 600259 次
  • 来自: ...
社区版块
存档分类
最新评论

Kruskal算法和prim算法求最小生成树学习小结(JAVA)

    博客分类:
阅读更多
   prim算法是用来实现图最小生成树的2种常用方法之一,Prim算法的主要步骤如下:


  1.设图的顶点集为V,首先选取一个点作为起始点,比如说1顶点,加入到U集合中

    2.在所有u∈U,v∈V-U的边(u,v)∈E中,找一条权最小的边(u,v),将此边加进集合T中,并将此边的非U中顶点加入U中。此步骤的功能是在边集E中找一条边,要求这条边满足以下条件:首先边的两个顶点要分别在顶点集合U和V-U中,其次边的权要最小。找到这条边以后,把这条边放到边集T中,并把这条边上不在U中的那个顶点加入到U中。

     3:如果U=V,则算法结束;否则重复步骤2。可以把本步骤看成循环终止条件。
我们可以算出当U=V时,步骤2共执行了n-1次(设n为图中顶点的数目),T中也增加了n-1条边,这n-1条边就是需要求出的最小生成树的边。

例题:给出t组数据,每组数据给出图的顶点数n,然后下面是n*n的无向图邻接矩阵表示,求最小生成树中权最大的边的权值。样例如下:


Sample Input

1

3
0 990 692
990 0 179
692 179 0

Sample Output

692

解法一:Prim算法代码
import java.util.Scanner;
public class Main{

  private int prim[][];//图的邻接矩阵
  private boolean visit[];//记录顶点是否被访问,即是否加入到了顶点集U
  private int Len[];  //Len[i] 记录顶点集U到i的最短距离,即U中所有点到i的距离之最小者。
  private int n;//顶点数
  int ans;

   public Main(int n,int[][] prim){
      this.n=n;
      this.prim=prim;
      visit=new boolean[n+1];//开始时都未访问
      Len=new int[n+1];
    }

   private int  prim_solve(int xx){
    int minx;int k=0;
      
    ans = -1;
    for (int i = 1; i <= n; i++)
    {
        Len[i] = prim[xx][i];
    }
    Len[xx] = 0;
    visit[xx] = true;  //此时U中只有起点xx
    for(int i = 1; i< n; i++)  // 注意:因为xx起点已经访问过,所以只需再访问n-1个
    {
        minx = Integer.MAX_VALUE;
        for(int j = 1; j <= n; j++ )   //在所有u∈U,v∈V-U的边(u,v)∈E中,找一条权最小的边(u,v)
        {                          //这里找的是:与顶点集U相邻的距离最小值
            if ( !visit[j]  && Len[j] < minx)
            {
                minx= Len[j];
                k = j;
            }
        }
        visit[k] = true;   //找到,加入U
        if (ans < minx)   //保存最短路径中最大的一条边
        {
            ans = minx;
        }
        //i=1时,U中只有起点xx和新加入的k,Len[j]与prim[k][j]比较:就是比较xx到j的距离和新加入U的k顶点到j的距离
        //之后,Len[j]就是U到j的最短距离啦,这样把U中所有顶点看成一个,Len[j]就是U到j(V-U中任意一个)的最短距离
        //以此类推,i>1 时,每次都把原来的顶点集U到j的距离和新加入的k到j的距离比较,这样得到了新U到j的最短距离
        //从而,就得到了新U到V-U中任一顶点的距离,保存在 Len中
        for (int j = 1; j <= n; j++)   
        {
            if ( !visit[j] && Len[j] > prim[k][j])
            {
                Len[j] = prim[k][j];
            }
        }
    }
    return ans;
   }

   public static void main(String[] args){
    Scanner in=new Scanner(System.in);
    int T=in.nextInt();
    while((T--)>0){
      int n=in.nextInt();
      int[][] prim=new int[n+1][n+1];
      for(int i = 1; i <= n; i++)
         for(int j = 1; j <= n; j ++){
                prim[i][j]=in.nextInt();
          }
      Main m=new Main(n,prim);
      System.out.printf("%d\n",m.prim_solve(1)); //以第一个顶点开始,也可以是其他
    }
  
  }
}




解法二、kruskal算法
  kruskal算法其实也是和prim算法一样求无向图的最小生成树,也属于贪心算法,不过prim算法的复杂度为O(n^2),适用于稠密图,而kruskal算法的复杂度为O(eloge),适用于稀疏图。

kruskal算法描述很容易理解,如下

  1.设连通网N=(V,{E}),令最小生成树初始状态为只有n个顶点而无边的非连通图T=(V,{F}),每个顶点自成一个连通分量

2.在E中选取代价最小的边,加入到T中,若它的添加使T 中产生回路,则舍去此边,选取下一条代价最小的边

3.依此类推,直至T中有 n-1 条边为止

Kruskal算法牵涉到集合操作,包括集合的建立和集合的合并,这里用并查集解决。

初始化:把每个节点所在结合初始化为自身。
查找:查找元素所在的集合,即根节点
合并:将两个在不同集合的元素合并为一个集合,应将树深度小的合并到深度大的上面或将子孙少的合并到子孙多的上面。

import java.util.Scanner;   
import java.util.Arrays;   
public class Main{   
    private int father[];   
    private int son[];   
    private Edge e[];   
    private int n;//结点个数   
    private int l;//边的数目   
          
    public Main(int n,int l,Edge[] e){   
       this.n=n;   
       this.l=l;   
       this.e=e;   
       father=new int[n];   
       son=new int[n];   
        for(int i = 0; i < n; ++i){      
            father[i] = i;//将每个顶点初始化为一个集合,父节点指向自己。   
            son[i]=1;//初始化每个父节点的儿子数为1   
        }           
    }      
  

    public int unionsearch(int x){ //查找根结点   
       return (x == father[x]) ? x : unionsearch(father[x]);     
    }     
     
    public boolean join(int x, int y){ //合并      
       int root1, root2;     
       root1 = unionsearch(x);     
       root2 = unionsearch(y);     
       if(root1 == root2){ //为环      
          return false;     
       }   
       else if(son[root1] >= son[root2]){     
            father[root2] = root1;     
            son[root1] += son[root2];     
        }     
        else     
        {     
            father[root1] = root2;     
            son[root2] += son[root1];     
        }     
        return true;     
     }     
  
  
     public int kruskal(){   
        int ans=0;   
        int ltotal=0;   
           
        Arrays.sort(e); //按权值由小到大排序      
        for(int i = 0; i < l; ++i)     
        {     
            if(join(e[i].a, e[i].b)==true)     
            {     
                ltotal++; //边数加1      
                ans= e[i].weight; //记录      
                
            }     
            if(ltotal == n - 1) //最小生成树条件:边数=顶点数-1      
            {     
                   
                return ans;
            }     
        }     
        return 0;
    }   
  
 
   public static void main(String[] args){
    Scanner in=new Scanner(System.in);
    int temp=0;
    int T=in.nextInt();
    while((T--)>0){
      int k=0;
      int n=in.nextInt();
      Edge[] e=new Edge[n*(n-1)/2];
      for(int i = 0; i < n; i++){
         for(int j = 0; j < n; j ++){
              if(i<j){//只读取上三角
                e[k]=new Edge(i,j,in.nextInt());
                k++;
              }else{
                  temp=in.nextInt();
              }
           
          }
      }
      Main m=new Main(n,k,e);
      System.out.printf("%d\n",m.kruskal()); 
    }
  
  }
}

class Edge implements Comparable    
  
{     
     int a;  //边的一个顶点,从数字0开始   
     int b;  //边的另一个顶点   
     int weight;  //权重   
  
     Edge(int a,int b,int weight){   
      this.a=a;   
      this.b=b;   
      this.weight=weight;   
    }   
  
    @Override      
    public int compareTo(Object o){    
        Edge m = (Edge)o;    
        int result=(int)(this.weight - m.weight);    
        if(result>0) return 1;   
        else if(result==0) return 0;   
        else return -1;   
    }    
  
}  

源码下载:
分享到:
评论

相关推荐

    Prim算法与Kruskal算法求最小生成树

    1. **引言**:介绍最小生成树的概念,以及Prim和Kruskal算法的基本思想。 2. **算法描述**:详细解释两种算法的步骤,包括伪代码或流程图。 3. **实现细节**:展示如何用编程语言(如C++、Java或Python)实现这两种...

    用Prim和Kruskal算法构造最小生成树

    ### 使用Prim和Kruskal算法构建最小生成树 在图论中,最小生成树(Minimum Spanning Tree, MST)是一个非常重要的概念。对于一个连通的无向图来说,如果存在一个子图,它包含原图的所有顶点,并且这些顶点通过边...

    prim和kruskal算法求最小生成树

    总的来说,Prim和Kruskal算法都是解决最小生成树问题的有效方法,它们各有优劣,适用于不同的图类型。在实际应用中,可以根据具体情况选择合适的算法,或者结合其他方法,如Edmonds-Karp算法,以提高效率。通过学习...

    cpp-图论算法最小生成树Prim算法和Kruskal算法C实现

    本文将详细介绍两种经典算法来解决最小生成树问题:Prim算法和Kruskal算法,并以C语言实现为例进行讲解。 ### Prim算法 Prim算法是一种贪心算法,其基本思想是从一个初始节点开始,逐步添加最短的边,直到连接到...

    最小生成树 prim算法和Kruskal算法实现

    prim算法 Kruskal算法分别实现最小生成树

    Prim与Kruskal算法的最小生成树matlab实现

    在通信网理论作业3-最小生成树这个项目中,你可能会学习如何用MATLAB编写代码,实现Prim和Kruskal算法,并对给定的网络图数据进行最小生成树的构造。这将涉及到数据结构的设计、图的遍历以及最小生成树的验证等编程...

    kruskal算法求最小生成树 java

    ### Kruskal算法求最小生成树的Java实现 #### 一、Kruskal算法简介 Kruskal算法是一种用于寻找图中的最小生成树(Minimum Spanning Tree, MST)的算法。最小生成树是指在一个加权无向图中,连接所有顶点形成的树,...

    PRIM算法,求最小生成树

    在实际应用中,PRIM算法常与Kruskal算法一起被提及,Kruskal算法是另一种解决最小生成树问题的方法,它通过选择权值最小的边并避免形成环来构建树。两者各有优劣,适用于不同的数据结构和场景。 总之,PRIM算法是...

    C++ Prim算法Kruskal算法构造可以使n个城市连接的最小生成树

    (1)、实验题目:给定一个地区的n 个城市间的距离网,用Prim算法或Kruskal算法建立最小生成树,并得到的最小生成树的代价。 (2)、实验要求: 1、城市间的距离网采用的邻接矩阵表示,邻接矩阵的存储结构定义采用...

    用Java利用prim算法实现最小生成树

    ### 使用Prim算法实现最小生成树 #### 一、最小生成树简介 最小生成树(Minimum Spanning Tree, MST)是指在一个加权的无向图中找到一棵包含所有顶点的生成树,使得所有边的权重之和最小。最小生成树在实际应用中...

    Prim和Kruskal算法求最小生成树

    win32控制台程序 vs2010以上编译运行通过 在main函数里定义图,然后调用2个封好的函数用2种不同的算法输出最小生成树 大连理工大学软件学院数据结构上机题

    最小生成树kruskal算法

    ### 最小生成树Kruskal算法详解 #### 算法背景与定义 最小生成树(Minimum Spanning Tree,...尽管在处理稠密图时可能不如Prim算法高效,但Kruskal算法的简单性和易于理解使其成为学习图算法和数据结构的一个好例子。

    Kruskal算法求最小生成树问题_matlab_生成树问题_

    最小生成树问题在图论中是一项基础而重要的任务,它涉及到如何从一个加权无向图中找到一棵包括所有顶点的树,使得这棵树的所有边的权重之和尽可能小。Kruskal算法就是解决这一问题的一种有效方法,由Joseph B. ...

    图的深度优先搜索,广度优先搜索,最小生成树算法,包括kruskal、prim算法的C++实现代码

    图的深度优先搜索,广度优先搜索,最小生成树算法,包括kruskal、prim算法的代码,以及详细的注释。深度优先应用递归、广度优先搜索利用队列、kruskal利用STL中的关联容器set、prim算法利用二叉堆结构进行优化。

    头歌数据结构图的最小生成树算法

    // 该函数使用邻接矩阵存储结构,通过Prim算法构建最小生成树 } ``` ##### 2.2.2 邻接表存储 ```c void MiniSpanTree_PRIM(ALGraph G, VertexType u) { // 代码实现省略,参见给定文件 // 该函数使用邻接表存储...

    数据结构 图的最小生成树 C++描述 使用prim算法、kruskal算法

    综上所述,最小生成树是图论中的核心问题,Prim算法和Kruskal算法是解决该问题的两种高效方法。在C++中,这两个算法都可以利用标准库提供的功能来实现,从而在复杂度和空间效率上达到较好的平衡。理解并熟练掌握这些...

    Kruskal算法生成最小代价生成树

    常见的最小代价生成树算法有Kruskal算法和Prim算法。 Kruskal算法的具体步骤如下: 1. **边的排序**:将图中的所有边按照权重从小到大进行排序。这一步可以通过各种排序算法实现,如快速排序、归并排序等。在这里...

    普里姆(Prim)算法构造最小生成树

    理解并熟练运用普里姆算法,不仅可以解决最小生成树的问题,还能为学习其他图算法如Kruskal算法打下基础,同时也对理解和优化复杂网络系统有重要意义。在数据结构和算法的学习过程中,掌握这些基本算法对于提升编程...

    最小生成树Kruskal和Prim算法讨论 (2).docx

    最小生成树Kruskal和Prim算法讨论 最小生成树(Minimum Spanning Tree,MST)是图论中的一种基本概念,指的是连接所有顶点的生成树中权值最小的那棵树。Kruskal算法和Prim算法是两种常用的构造MST的算法,这两种...

Global site tag (gtag.js) - Google Analytics