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

        最小生成树包含n个顶点和(n-1)条边,并且边的权重最小。Prim算法的思想是:由一颗小树慢慢长大,首先分为两个顶点集合,最小生成树的顶点集合A,和不在生成树中的顶点集合B,每次从B中找一个顶点v,使其到A中的某个顶点的权重最小,并将v放入A,同时从B删除。以下图为例(图中的数字即为权重),进行简单的说明:

 

步骤如下(以v1为起点):

(1)一开始,集合A只有顶点v1,剩下的顶点在集合B中,即A={v1}、B={v2,v3,v4,v5,v6,v7}

 (2)从B中找一个顶点v,使其到A中的某个顶点的权重最小,从图中可以看出,v4到v1的权重最小,所以将v4收入到最小生成树的集合中A,此时A={v1,v4}、B={v2,v3,v5,v6,v7}

(3)重复步骤(2),当前A={v1,v4}、B={v2,v3,v5,v6,v7},从图中看出,(v1,v2)=2,、(v3,v4)=2,两条边的权重一样大,都是最小的,那么我们既可以收入顶点v2,也可以收入顶点v3,那么我们按顶点顺序,先收入顶点v2,即此时A={v1,v2,v4}、B={v3,v5,v6,v7}

(4)重复步骤(2),由于顶点v3到顶点v4的权重最小,为2,故收入顶点v3到A中,此时A={v1,v4,v2,v3}、B={v5,v6,v7}

(5)重复步骤(2),由于(v1,v3)=4,、(v4,v7)=4的权重都是最小的,但是顶点v3已经在集合A中了,故不能收入,否则就会出现环,所以应该收入顶点v7,即此时A={v1,v4,v2,v3,v7}、B={v5,v6}

(6)重复步骤(2),v7收入到集合A后,发现到顶点的v6的权重为1,是最小的了,故收入顶点v6到集合A中,即此时A={v1,v4,v2,v3,v7,v6}、B={v5}

(7)将顶点v5收入到集合A中,即此时A={v1,v4,v2,v3,v7,v6,v5}、B={},至此,所有顶点都已经收集完了,由这些顶点及收入顶点过程中边组成的,便是最小生成树了。

 

       从以上步骤也可以看出,Prim算法就是一个收集顶点的过程,只不过它每次都收集权重最小的边的顶点,是一种贪心算法的思想。

 

Java代码实现:

(1)顶点结构:

//图的顶点类型
class Vertex {
    public char value;   //顶点值
    public boolean visited; //顶点是否被访问过

    public Vertex(char v) {
        value=v;
        visited=false;
    }
}

(2)边的结构

//存储边的两个顶点及边的权值
class Edge{
    public int u;  //顶点
    public int v;  //顶点
    public int w; //权值
    public Edge(int u,int v,int w) {
        this.u=u;
        this.v=v;
        this.w=w;
    }
}

(3)prim算法实现

//Prim算法解决最小生成树问题,以顶点为思考对象
    //Prim算法思想:由一颗小树慢慢长大,首先分为两个顶点集合,树的顶点集合A,和不在生成树中的顶点集合B,每次从B中找一个顶点v,
    // 使其到A中的某个顶点的权重最小,并将v放入A,同时从B删除
    public void prim(int start) {
        int[] prims=new int[vertexList.length]; //记录最小生成树的顶点序号
        //初始化
        for(int i=0;i<vertexList.length;i++) {
            distance[i]=mGraph[start][i];  //到起点的权值
            prims[i]=-1;
        }
        distance[start]=0;  //自己到自己的距离为0
        int index=0;  //最小生成树的索引
        prims[index++]=start;

        for(int i=0;i<vertexList.length;i++) {
            if(i==start) {
                continue;
            }
            int min=Integer.MAX_VALUE;
            int k=-1;
            for(int j=0;j<vertexList.length;j++) {
                //distance[j]==0,表示已经在最小生成树中
                //如果不在最小生成树中,并且与最小生成树中的某个顶点组成的边的权值更小
                if(distance[j]!=0 && distance[j]<min) {
                    min=distance[j];
                    k=j;
                }
            }

            //循环结束后,第k个顶点就是和已经收录的顶点构成边权值最小的顶点
            prims[index++]=k;
            distance[k]=0;  //到最小生成树的距离为0,表示已经在最小生成树中
            //更新第k个顶点到未被收录进最小生成树中邻接点的权值
            for(int j=0;j<vertexList.length;j++) {
                //如果j是k的未被收录的邻接点,mGraph[k][j],是顶点k到顶点j的距离
                if(distance[j]!=0 && mGraph[k][j] < distance[j]) {
                    distance[j]=mGraph[k][j];  // 更新顶点j到生成树的距离
                }
            }
        }

        //打印最小生成树
        for(int i=0;i<vertexList.length;i++) {
            System.out.print(vertexList[prims[i]].value+" ");
        }
        //打印最小权值:从最小生成树的第二个顶点开始,找它到前驱顶点的最小权值
        int sum=0;
        //一共n-1条边
        for(int i=1;i<vertexList.length;i++) {
            int min=Integer.MAX_VALUE;
            for(int j=0;j<i;j++) {
                if(mGraph[prims[j]][prims[i]]<min) {
                    //prims[j]表示已经在最小生成树中的顶点
                    min=mGraph[prims[j]][prims[i]];
                }
            }
            sum+=min;
        }
        System.out.println("最小权值和为:"+sum);
    }

完整代码,请参考:https://blog.csdn.net/qiuxinfa123/article/details/83719789

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值