JAVA数据结构与算法之————最小生成树

Kruskal算法和Prim算法

Kruskal

Kruskal算法是用来计算加权连通图的最小生成树的算法。
基本思想:按照权值从小到大的顺序选择n-1条边,并保证这n-1条边不构成回路。
边结构:

public static class Edge{
        int begin;
        int end;
        int weight;
        public Edge(){}
        public Edge(int begin, int end, int weight){
            this.begin = begin;
            this.end = end;
            this.weight = weight;
        }
    }

Kruskal

/*
    *G的存储结构为邻接矩阵
    *计算最小生成树 
    * */
    public void MinSpanTree(MGraph G){

        /*connect 判断加入的边是否使图构成回路*/
        int[] connect = new int[G.getNumVertexes()];
        /*获取图中的全部的边*/
        Edge[] edges = getEdges(G.getArc(), G.getNumEdgs());
        /*将边按权重从小到大排序*/
        sortedEdges(edges);
        /*初始化connect*/
        for(int i = 0; i < connect.length; i++){
            connect[i] = -1;
        }
        
        for(int i = 0; i < G.getNumEdgs(); i++){
            /*如果n==m说明加入边edges[i]是图中出现回路*/
            int n = find(connect, edges[i].begin);
            int m = find(connect, edges[i].end);
            if(n != m){
                connect[n] = m;
                System.out.println(edges[i].begin + " " + edges[i].end + " " + edges[i].weight);
            }
        }
    }

    /*获取全部的边*/
    private Edge[] getEdges(int[][] arc, int numEdgs){
        List<Edge> edges = new ArrayList<>();
        Edge[] e = new Edge[numEdgs];
        int count = 0;
        for(int i = 1; i < arc.length; i++){
            for(int j = 0; j < i; j++){
                if(arc[i][j] < Integer.MAX_VALUE){
                    edges.add(new Edge(i, j, arc[i][j]));
                    count++;
                }
            }
        }
        System.out.println(count);
        return edges.toArray(e);
    }

    /*将边按权重从小到大排序*/
    private void sortedEdges(Edge[] edges){

        for(int i = 0; i < edges.length - 1; i++){
            for(int j = i + 1; j < edges.length; j++){
                if(edges[i].weight > edges[j].weight){
                    Edge temp = edges[i];
                    edges[i] = edges[j];
                    edges[j] = temp;
                }
            }
        }
    }

    
    private int find(int[] connect, int f){
        while(connect[f]  > -1){
            f = connect[f];
        }
        return f;
    }

Prim

Prim算法求最小生成树的时候和边数无关,和顶点树有关,所以适合求解稠密网的最小生成树。
基本思想:将图中的点分为两部分,一部分是没有访问的点集U,另一部分是访问过的点集V,然后在访问过的点集中寻找边权重最小的边的另一个节点加入。重复,直到U为空,V中包含了全部的点。

package graph;

import graph.graphadjlist.EdgeNode;
import graph.graphadjlist.GraphAdjList;
import graph.graphadjlist.VertexNode;

import java.util.ArrayList;
import java.util.List;

/*
 * 图的存储结构为邻接表
 * prim算法计算最小生成树
 * */
public class MinSpanTreePrim {

    public void getMinSpanTree(GraphAdjList<VertexNode> G) {

        /*第一个节点加入到点集V*/
        G.adjList.get(0).isVisited = true;


        int count = 1;
        /*直到全部点都访问过循环结束*/
        while (count < G.numVertexes) {

            int min = Integer.MAX_VALUE;
            int temp = -1;

            /*一次循环点集V,找到最小边的另一个点
            * 加入到V中
            * */
            for (int i = 0; i < G.numVertexes; i++) {

                if (G.adjList.get(i).isVisited == true) {

                    EdgeNode e = G.adjList.get(i).firstedge;
                    while (e != null) {

                        for (int j = 0; j < G.numVertexes; j++) {
                            if (G.adjList.get(j).data.compareTo(e.adjvex) == 0 && G.adjList.get(j).isVisited == false && e.weight < min) {
                                temp = j;
                                min = e.weight;
                                break;
                            }
                        }

                        e = e.next;

                    }
                }
            }
            /*加入点G.adjList.get(temp)到点集V中*/
            G.adjList.get(temp).isVisited = true;
            System.out.println(G.adjList.get(temp).data);
            System.out.println(min);
            count++;
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值