欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實現(xiàn)最小生成樹MST的兩種解法

 更新時間:2022年05月26日 11:07:06   作者:愛編程的MG  
最小生成樹(MST)指在連通圖的所有生成樹中,所有邊的權(quán)值和最小的生成樹。本文介紹了求最小生成樹的兩種方法:Prim算法和Kruskal算法,需要的可以參考一下

一、prim算法

時間復(fù)雜度較之kruskal較高

通俗的解釋就是:

(1)從哪個點開始生成最小生成樹都一樣,最后的權(quán)值都是相同的

(2)從哪個點開始,先標記這個點是訪問過的,用visited數(shù)組表示所有節(jié)點的訪問情況

(3)訪問節(jié)點開始都每個沒訪問結(jié)點的距離選取形成的邊的權(quán)值最小值

綜合以上三點就是我們prim算法寫代碼實現(xiàn)的重要思路

代碼實現(xiàn):

package Prim;
 
import java.util.Arrays;
 
public class PrimAlgorithm {
    public static void main(String[] args) {
        //測試看看圖是否創(chuàng)建ok
        char[] data = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G'};
        int verxs = data.length;
        //鄰接矩陣的關(guān)系使用二維數(shù)組表示,10000這個大數(shù),表示兩個點不聯(lián)通
        int[][] weight = new int[][]{
                {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},};
        MGraph mGraph = new MGraph(verxs);
        MinTree minTree = new MinTree();
        minTree.createGraph(mGraph, verxs, data, weight);
        minTree.showGraph(mGraph);
        minTree.Prim(mGraph, 0);
    }
}
 
class MinTree {
    /**
     * 創(chuàng)造圖
     * @param graph  圖對象
     * @param verxs  圖節(jié)點個數(shù)
     * @param data   圖每個頂點的數(shù)據(jù)值
     * @param weight 圖的邊(鄰接矩陣)
     */
    public void createGraph(MGraph graph, int verxs, char[] data, int[][] weight) {
        int i, j;
        for (i = 0; i < verxs; i++) {
            graph.data[i] = data[i];
            for (j = 0; j < verxs; j++) {
                graph.weight[i][j] = weight[i][j];
            }
        }
    }
 
    // 顯示圖的鄰接矩陣
    public void showGraph(MGraph graph) {
        for (int[] link : graph.weight) {
            System.out.println(Arrays.toString(link));
        }
    }
 
    /**
     * 編寫prim算法
     *
     * @param graph 圖對象
     * @param v     從哪個節(jié)點開始生成最小生成樹
     */
    public void Prim(MGraph graph, int v) {
        //定義一個數(shù)組,判斷節(jié)點是不是被訪問過了
        int[] visited = new int[graph.verxs];
        //v這個點已經(jīng)被訪問了,從這個點開始訪問
        visited[v] = 1;
        //找到節(jié)點下標
        int h1 = -1;
        int h2 = -1;
        int minWeight = 10000;//定義初始值為最大值,只要出現(xiàn)小的就會替換
        int sum = 0;
        // 從1開始循環(huán),相當于就是生成graph.verx - 1條邊
        for (int k = 1; k < graph.verxs; k++) {
 
            for (int i = 0; i < graph.verxs; i++) {//遍歷已經(jīng)訪問過的點
                if (visited[i] == 1){
                    for (int j = 0; j < graph.verxs; j++) {//遍歷沒有訪問過的點
                        //在未訪問點中尋找所有與訪問過的點相連的邊中權(quán)值最小值
                        if (visited[i] == 1 && visited[j] == 0 && graph.weight[i][j] < minWeight) {
                            minWeight = graph.weight[i][j];
                            h1 = i;
                            h2 = j;
                        }
                    }
                }
            }
            sum += minWeight; // 求最小生成熟的總權(quán)值
            //此時已經(jīng)找到一條邊是最小了
            System.out.println("邊<" + graph.data[h1] + "," + graph.data[h2] + "> 權(quán)值:" + minWeight);
            //然后標記點
            visited[h2] = 1;
            //將權(quán)值重新變成最大值
            minWeight = 10000;
        }
        System.out.println("最小生成樹的權(quán)值是:" + sum);
 
    }
}
 
// 圖
class MGraph {
    int verxs; // 表示圖節(jié)點個數(shù)
    char[] data; // 表示節(jié)點數(shù)據(jù)
    int[][] weight; // 表示邊
 
    public MGraph(int verxs) {
        this.verxs = verxs;
        data = new char[verxs];
        weight = new int[verxs][verxs];
    }
}

二、kruskal算法

時間復(fù)雜度低一些,但是代碼量會大一些

對克魯斯卡爾算法的通俗解釋:

(1)對每條邊的權(quán)值進行排序

(2)按照從小到大依次選取邊構(gòu)成最小生成樹,但是要注意是否構(gòu)成回路,樹的概念是不能生成回路

(3)此處用的方法比較巧妙使用了getEnd方法來判斷兩者終點是不是一樣,用ends數(shù)組保存最小生成樹中每個頂點的終點

代碼實現(xiàn):

package Kruskal;
 
import java.util.Arrays;
 
public class KruskalCase {
 
    private int edgeNum; //邊的個數(shù)
    private char[] vertexs; //頂點數(shù)組
    private int[][] matrix; //鄰接矩陣
    //使用 INF 表示兩個頂點不能連通
    private static final int INF = Integer.MAX_VALUE;
 
    public static void main(String[] args) {
        char[] vertexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
        //克魯斯卡爾算法的鄰接矩陣
        int matrix[][] = {
                /*A*//*B*//*C*//*D*//*E*//*F*//*G*/
                /*A*/ {0, 12, INF, INF, INF, 16, 14},
                /*B*/ {12, 0, 10, INF, INF, 7, INF},
                /*C*/ {INF, 10, 0, 3, 5, 6, INF},
                /*D*/ {INF, INF, 3, 0, 4, INF, INF},
                /*E*/ {INF, INF, 5, 4, 0, 2, 8},
                /*F*/ {16, 7, 6, INF, 2, 0, 9},
                /*G*/ {14, INF, INF, INF, 8, 9, 0}};
        //大家可以在去測試其它的鄰接矩陣,結(jié)果都可以得到最小生成樹.
 
        //創(chuàng)建KruskalCase 對象實例
        KruskalCase kruskalCase = new KruskalCase(vertexs, matrix);
        //輸出構(gòu)建的
        kruskalCase.print();
        kruskalCase.kruskal();
 
    }
 
    //構(gòu)造器
    public KruskalCase(char[] vertexs, int[][] matrix) {
        //初始化頂點數(shù)和邊的個數(shù)
        int vlen = vertexs.length;
 
        //初始化頂點, 復(fù)制拷貝的方式
        this.vertexs = new char[vlen];
        for (int i = 0; i < vertexs.length; i++) {
            this.vertexs[i] = vertexs[i];
        }
 
        //初始化邊, 使用的是復(fù)制拷貝的方式
        this.matrix = new int[vlen][vlen];
        for (int i = 0; i < vlen; i++) {
            for (int j = 0; j < vlen; j++) {
                this.matrix[i][j] = matrix[i][j];
            }
        }
        //統(tǒng)計邊的條數(shù)
        for (int i = 0; i < vlen; i++) {
            for (int j = i + 1; j < vlen; j++) {
                if (this.matrix[i][j] != INF) {
                    edgeNum++;
                }
            }
        }
 
    }
 
    public void kruskal() {
        int index = 0; //表示最后結(jié)果數(shù)組的索引
        int[] ends = new int[edgeNum]; //用于保存"已有最小生成樹" 中的每個頂點在最小生成樹中的終點
        //創(chuàng)建結(jié)果數(shù)組, 保存最后的最小生成樹
        EData[] rets = new EData[edgeNum];
 
        //獲取圖中 所有的邊的集合 , 一共有12邊
        EData[] edges = getEdges();
        System.out.println("圖的邊的集合=" + Arrays.toString(edges) + " 共" + edges.length); //12
 
        //按照邊的權(quán)值大小進行排序(從小到大)
        sortEdges(edges);
 
        //遍歷edges 數(shù)組,將邊添加到最小生成樹中時,判斷是準備加入的邊否形成了回路,如果沒有,就加入 rets, 否則不能加入
        for (int i = 0; i < edgeNum; i++) {
            //獲取到第i條邊的第一個頂點(起點)
            int p1 = getPosition(edges[i].start); //p1=4
            //獲取到第i條邊的第2個頂點
            int p2 = getPosition(edges[i].end); //p2 = 5
 
            //獲取p1這個頂點在已有最小生成樹中的終點
            int m = getEnd(ends, p1); //m = 4
            //獲取p2這個頂點在已有最小生成樹中的終點
            int n = getEnd(ends, p2); // n = 5
            //是否構(gòu)成回路
            if (m != n) { //沒有構(gòu)成回路
                ends[m] = n; // 設(shè)置m 在"已有最小生成樹"中的終點 <E,F> [0,0,0,0,5,0,0,0,0,0,0,0]
                rets[index++] = edges[i]; //有一條邊加入到rets數(shù)組
            }
        }
        //<E,F> <C,D> <D,E> <B,F> <E,G> <A,B>。
        //統(tǒng)計并打印 "最小生成樹", 輸出  rets
        System.out.println("最小生成樹為");
        for (int i = 0; i < index; i++) {
            System.out.println(rets[i]);
        }
 
 
    }
 
    //打印鄰接矩陣
    public void print() {
        System.out.println("鄰接矩陣為: \n");
        for (int i = 0; i < vertexs.length; i++) {
            for (int j = 0; j < vertexs.length; j++) {
                System.out.printf("%12d", matrix[i][j]);
            }
            System.out.println();//換行
        }
    }
 
    /**
     * 功能:對邊進行排序處理, 冒泡排序
     *
     * @param edges 邊的集合
     */
    private void sortEdges(EData[] edges) {
        for (int i = 0; i < edges.length - 1; i++) {
            for (int j = 0; j < edges.length - 1 - i; j++) {
                if (edges[j].weight > edges[j + 1].weight) {//交換
                    EData tmp = edges[j];
                    edges[j] = edges[j + 1];
                    edges[j + 1] = tmp;
                }
            }
        }
    }
 
    /**
     * @param ch 頂點的值,比如'A','B'
     * @return 返回ch頂點對應(yīng)的下標,如果找不到,返回-1
     */
    private int getPosition(char ch) {
        for (int i = 0; i < vertexs.length; i++) {
            if (vertexs[i] == ch) {//找到
                return i;
            }
        }
        //找不到,返回-1
        return -1;
    }
 
    /**
     * 功能: 獲取圖中邊,放到EData[] 數(shù)組中,后面我們需要遍歷該數(shù)組
     * 是通過matrix 鄰接矩陣來獲取
     * EData[] 形式 [['A','B', 12], ['B','F',7], .....]
     *
     * @return
     */
    private EData[] getEdges() {
        int index = 0;
        EData[] edges = new EData[edgeNum];
        for (int i = 0; i < vertexs.length; i++) {
            for (int j = i + 1; j < vertexs.length; j++) {
                if (matrix[i][j] != INF) {
                    edges[index++] = new EData(vertexs[i], vertexs[j], matrix[i][j]);
                }
            }
        }
        return edges;
    }
 
    /**
     * 功能: 獲取下標為i的頂點的終點(), 用于后面判斷兩個頂點的終點是否相同
     *
     * @param ends : 數(shù)組就是記錄了各個頂點對應(yīng)的終點是哪個,ends 數(shù)組是在遍歷過程中,逐步形成
     * @param i    : 表示傳入的頂點對應(yīng)的下標
     * @return 返回的就是 下標為i的這個頂點對應(yīng)的終點的下標, 一會回頭還有來理解
     */
    private int getEnd(int[] ends, int i) { // i = 4 [0,0,0,0,5,0,0,0,0,0,0,0]
        while (ends[i] != 0) {
            i = ends[i];
        }
        return i;
    }
 
}
 
//創(chuàng)建一個類EData ,它的對象實例就表示一條邊
class EData {
    char start; //邊的一個點
    char end; //邊的另外一個點
    int weight; //邊的權(quán)值
 
    //構(gòu)造器
    public EData(char start, char end, int weight) {
        this.start = start;
        this.end = end;
        this.weight = weight;
    }
 
    //重寫toString, 便于輸出邊信息
    @Override
    public String toString() {
        return "EData [<" + start + ", " + end + ">= " + weight + "]";
    }
 
 
}

到此這篇關(guān)于Java實現(xiàn)最小生成樹MST的兩種解法的文章就介紹到這了,更多相關(guān)Java最小生成樹內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring?IoC容器Bean作用域的singleton與prototype使用配置

    Spring?IoC容器Bean作用域的singleton與prototype使用配置

    這篇文章主要為大家介紹了Spring?IoC容器Bean作用域的singleton與prototype使用配置詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • Java?Timer使用講解

    Java?Timer使用講解

    Timer是一種工具,線程用其安排以后在后臺線程中執(zhí)行的任務(wù)??砂才湃蝿?wù)執(zhí)行一次,或者定期重復(fù)執(zhí)行,這篇文章主要介紹了Java?Timer使用講解,需要的朋友可以參考下
    2022-11-11
  • MyBatis JdbcType 與Oracle、MySql數(shù)據(jù)類型對應(yīng)關(guān)系說明

    MyBatis JdbcType 與Oracle、MySql數(shù)據(jù)類型對應(yīng)關(guān)系說明

    這篇文章主要介紹了MyBatis JdbcType 與Oracle、MySql數(shù)據(jù)類型對應(yīng)關(guān)系說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 詳解servlet配置load-on-startup的作用

    詳解servlet配置load-on-startup的作用

    本文對load-on-startup的相關(guān)內(nèi)容作了詳細介紹,然后通過具體實例向大家展示了其作用,希望可以給大家一個參考。
    2017-09-09
  • JAVA中 redisTemplate 和 jedis的配合使用操作

    JAVA中 redisTemplate 和 jedis的配合使用操作

    這篇文章主要介紹了JAVA中 redisTemplate 和 jedis的配合使用操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java中ThreadLocal使用原理及Synchronized區(qū)別

    Java中ThreadLocal使用原理及Synchronized區(qū)別

    ThreadLocal叫做線程變量,本文詳細的介紹了ThreadLocal使用原理及Synchronized區(qū)別,有需要的朋友可以參考一下,希望對你有所幫助。
    2023-05-05
  • Java線程中斷機制interrupt、isInterrupted、interrupted方法詳解

    Java線程中斷機制interrupt、isInterrupted、interrupted方法詳解

    這篇文章主要介紹了Java線程中斷機制interrupt、isInterrupted、interrupted方法詳解,一個線程不應(yīng)該由其他線程來強制中斷或停止,而是應(yīng)該由線程自己自行停止,所以,Thread.stop、Thread.suspend、Thread. resume都已經(jīng)被廢棄了,需要的朋友可以參考下
    2024-01-01
  • Java 限制子類訪問的方法分析

    Java 限制子類訪問的方法分析

    這篇文章主要介紹了Java 限制子類訪問的方法,結(jié)合實例形式分析了java類的繼承與訪問相關(guān)操作技巧與使用注意事項,需要的朋友可以參考下
    2019-09-09
  • Java設(shè)計模式之命令模式詳解

    Java設(shè)計模式之命令模式詳解

    這篇文章主要介紹了Java設(shè)計模式之命令模式詳解,文中有非常詳細的代碼示例,對正在學(xué)習Java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • Java讀取json數(shù)據(jù)并存入數(shù)據(jù)庫的操作代碼

    Java讀取json數(shù)據(jù)并存入數(shù)據(jù)庫的操作代碼

    很多朋友問大佬們JAVA怎么把json存入數(shù)據(jù)庫啊,這一問題就把我難倒了,糾結(jié)如何操作呢,下面小編把我的經(jīng)驗分享給大家,感興趣的朋友一起看看吧
    2021-08-08

最新評論