最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

一、prim算法

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

通俗的解釋就是:

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

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

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

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

代碼實(shí)現(xiàn):

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

二、kruskal算法

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

對(duì)克魯斯卡爾算法的通俗解釋:

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

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

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

代碼實(shí)現(xiàn):

package Kruskal;
 
import java.util.Arrays;
 
public class KruskalCase {
 
    private int edgeNum; //邊的個(gè)數(shù)
    private char[] vertexs; //頂點(diǎn)數(shù)組
    private int[][] matrix; //鄰接矩陣
    //使用 INF 表示兩個(gè)頂點(diǎn)不能連通
    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}};
        //大家可以在去測(cè)試其它的鄰接矩陣,結(jié)果都可以得到最小生成樹.
 
        //創(chuàng)建KruskalCase 對(duì)象實(shí)例
        KruskalCase kruskalCase = new KruskalCase(vertexs, matrix);
        //輸出構(gòu)建的
        kruskalCase.print();
        kruskalCase.kruskal();
 
    }
 
    //構(gòu)造器
    public KruskalCase(char[] vertexs, int[][] matrix) {
        //初始化頂點(diǎn)數(shù)和邊的個(gè)數(shù)
        int vlen = vertexs.length;
 
        //初始化頂點(diǎn), 復(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)計(jì)邊的條數(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]; //用于保存"已有最小生成樹" 中的每個(gè)頂點(diǎn)在最小生成樹中的終點(diǎn)
        //創(chuàng)建結(jié)果數(shù)組, 保存最后的最小生成樹
        EData[] rets = new EData[edgeNum];
 
        //獲取圖中 所有的邊的集合 , 一共有12邊
        EData[] edges = getEdges();
        System.out.println("圖的邊的集合=" + Arrays.toString(edges) + " 共" + edges.length); //12
 
        //按照邊的權(quán)值大小進(jìn)行排序(從小到大)
        sortEdges(edges);
 
        //遍歷edges 數(shù)組,將邊添加到最小生成樹中時(shí),判斷是準(zhǔn)備加入的邊否形成了回路,如果沒有,就加入 rets, 否則不能加入
        for (int i = 0; i < edgeNum; i++) {
            //獲取到第i條邊的第一個(gè)頂點(diǎn)(起點(diǎn))
            int p1 = getPosition(edges[i].start); //p1=4
            //獲取到第i條邊的第2個(gè)頂點(diǎn)
            int p2 = getPosition(edges[i].end); //p2 = 5
 
            //獲取p1這個(gè)頂點(diǎn)在已有最小生成樹中的終點(diǎn)
            int m = getEnd(ends, p1); //m = 4
            //獲取p2這個(gè)頂點(diǎn)在已有最小生成樹中的終點(diǎn)
            int n = getEnd(ends, p2); // n = 5
            //是否構(gòu)成回路
            if (m != n) { //沒有構(gòu)成回路
                ends[m] = n; // 設(shè)置m 在"已有最小生成樹"中的終點(diǎn) <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)計(jì)并打印 "最小生成樹", 輸出  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();//換行
        }
    }
 
    /**
     * 功能:對(duì)邊進(jìn)行排序處理, 冒泡排序
     *
     * @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 頂點(diǎn)的值,比如'A','B'
     * @return 返回ch頂點(diǎn)對(duì)應(yīng)的下標(biāo),如果找不到,返回-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;
    }
 
    /**
     * 功能: 獲取下標(biāo)為i的頂點(diǎn)的終點(diǎn)(), 用于后面判斷兩個(gè)頂點(diǎn)的終點(diǎn)是否相同
     *
     * @param ends : 數(shù)組就是記錄了各個(gè)頂點(diǎn)對(duì)應(yīng)的終點(diǎn)是哪個(gè),ends 數(shù)組是在遍歷過程中,逐步形成
     * @param i    : 表示傳入的頂點(diǎn)對(duì)應(yīng)的下標(biāo)
     * @return 返回的就是 下標(biāo)為i的這個(gè)頂點(diǎn)對(duì)應(yīng)的終點(diǎn)的下標(biāo), 一會(huì)回頭還有來理解
     */
    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)建一個(gè)類EData ,它的對(duì)象實(shí)例就表示一條邊
class EData {
    char start; //邊的一個(gè)點(diǎn)
    char end; //邊的另外一個(gè)點(diǎn)
    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實(shí)現(xiàn)最小生成樹MST的兩種解法的文章就介紹到這了,更多相關(guān)Java最小生成樹內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java使用反射給對(duì)象屬性賦值的兩種方法

    java使用反射給對(duì)象屬性賦值的兩種方法

    JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法,下面這篇文章主要給大家介紹了關(guān)于java使用反射給對(duì)象屬性賦值的兩種方法,需要的朋友可以參考下
    2023-04-04
  • Java中常用的設(shè)計(jì)模式之觀察者模式詳解

    Java中常用的設(shè)計(jì)模式之觀察者模式詳解

    這篇文章主要為大家詳細(xì)介紹了Java中常用的設(shè)計(jì)模式之觀察者模式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • java模擬http的Get/Post請(qǐng)求,并設(shè)置ip與port代理的方法

    java模擬http的Get/Post請(qǐng)求,并設(shè)置ip與port代理的方法

    下面小編就為大家?guī)硪黄猨ava模擬http的Get/Post請(qǐng)求,并設(shè)置ip與port代理的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-02-02
  • Java實(shí)現(xiàn)經(jīng)典游戲黃金礦工的示例代碼

    Java實(shí)現(xiàn)經(jīng)典游戲黃金礦工的示例代碼

    《黃金礦工》游戲是一個(gè)經(jīng)典的抓金子小游戲,它可以鍛煉人的反應(yīng)能力。本文將用Java實(shí)現(xiàn)這一經(jīng)典的游戲,感興趣的小伙伴可以了解一下
    2022-02-02
  • spring?kafka?@KafkaListener詳解與使用過程

    spring?kafka?@KafkaListener詳解與使用過程

    這篇文章主要介紹了spring-kafka?@KafkaListener詳解與使用,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-02-02
  • 使用@SpringBootTest注解進(jìn)行單元測(cè)試

    使用@SpringBootTest注解進(jìn)行單元測(cè)試

    這篇文章主要介紹了使用@SpringBootTest注解進(jìn)行單元測(cè)試,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • java中public class與class的區(qū)別詳解

    java中public class與class的區(qū)別詳解

    以下是對(duì)java中public class與class的區(qū)別進(jìn)行了分析介紹,需要的朋友可以過來參考下
    2013-07-07
  • Java 10 局部變量類型推斷淺析

    Java 10 局部變量類型推斷淺析

    這篇文章主要介紹了Java 10 局部變量類型推斷淺析,Java 10 引進(jìn)一種新的閃閃發(fā)光的特性叫做局部變量類型推斷。文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下
    2019-06-06
  • Java使用線程池的優(yōu)勢(shì)有哪些

    Java使用線程池的優(yōu)勢(shì)有哪些

    這篇文章主要介紹了Java使用線程池的優(yōu)勢(shì)有哪些,幫助大家更好的理解和掌握java池化技術(shù),感興趣的朋友可以了解下
    2020-09-09
  • Java使用正則表達(dá)式實(shí)現(xiàn)找出數(shù)字功能示例

    Java使用正則表達(dá)式實(shí)現(xiàn)找出數(shù)字功能示例

    這篇文章主要介紹了Java使用正則表達(dá)式實(shí)現(xiàn)找出數(shù)字功能,結(jié)合實(shí)例形式分析了Java針對(duì)數(shù)字的匹配查找及非數(shù)字替換操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-03-03

最新評(píng)論

华阴市| 新竹县| 柞水县| 额敏县| 巴林左旗| 鄂尔多斯市| 紫云| 定远县| 锡林郭勒盟| 府谷县| 中卫市| 安乡县| 泰兴市| 孟村| 阿合奇县| 且末县| 万源市| 宜黄县| 克什克腾旗| 右玉县| 射阳县| 扶绥县| 望都县| 建始县| 芦山县| 阆中市| 凤庆县| 磐石市| 大同县| 吴桥县| 黎川县| 灵山县| 广州市| 绥江县| 蓬安县| 桦川县| 兴化市| 清镇市| 崇左市| 湘西| 江孜县|