亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

一、prim算法

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

通俗的解釋就是:

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

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

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

綜合以上三點(diǎn)就是我們prim算法寫(xiě)代碼實(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));
        }
    }
 
    /**
     * 編寫(xiě)prim算法
     *
     * @param graph 圖對(duì)象
     * @param v     從哪個(gè)節(jié)點(diǎn)開(kāi)始生成最小生成樹(shù)
     */
    public void Prim(MGraph graph, int v) {
        //定義一個(gè)數(shù)組,判斷節(jié)點(diǎn)是不是被訪問(wèn)過(guò)了
        int[] visited = new int[graph.verxs];
        //v這個(gè)點(diǎn)已經(jīng)被訪問(wèn)了,從這個(gè)點(diǎn)開(kāi)始訪問(wè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開(kāi)始循環(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)訪問(wèn)過(guò)的點(diǎn)
                if (visited[i] == 1){
                    for (int j = 0; j < graph.verxs; j++) {//遍歷沒(méi)有訪問(wèn)過(guò)的點(diǎn)
                        //在未訪問(wèn)點(diǎn)中尋找所有與訪問(wèn)過(guò)的點(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("最小生成樹(shù)的權(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)成最小生成樹(shù),但是要注意是否構(gòu)成回路,樹(shù)的概念是不能生成回路

(3)此處用的方法比較巧妙使用了getEnd方法來(lái)判斷兩者終點(diǎn)是不是一樣,用ends數(shù)組保存最小生成樹(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é)果都可以得到最小生成樹(shù).
 
        //創(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]; //用于保存"已有最小生成樹(shù)" 中的每個(gè)頂點(diǎn)在最小生成樹(shù)中的終點(diǎn)
        //創(chuàng)建結(jié)果數(shù)組, 保存最后的最小生成樹(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ù)中時(shí),判斷是準(zhǔn)備加入的邊否形成了回路,如果沒(méi)有,就加入 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)在已有最小生成樹(shù)中的終點(diǎn)
            int m = getEnd(ends, p1); //m = 4
            //獲取p2這個(gè)頂點(diǎn)在已有最小生成樹(shù)中的終點(diǎn)
            int n = getEnd(ends, p2); // n = 5
            //是否構(gòu)成回路
            if (m != n) { //沒(méi)有構(gòu)成回路
                ends[m] = n; // 設(shè)置m 在"已有最小生成樹(shù)"中的終點(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ì)并打印 "最小生成樹(shù)", 輸出  rets
        System.out.println("最小生成樹(shù)為");
        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ù)組
     * 是通過(guò)matrix 鄰接矩陣來(lái)獲取
     * 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ù)組是在遍歷過(guò)程中,逐步形成
     * @param i    : 表示傳入的頂點(diǎn)對(duì)應(yīng)的下標(biāo)
     * @return 返回的就是 下標(biāo)為i的這個(gè)頂點(diǎn)對(duì)應(yīng)的終點(diǎn)的下標(biāo), 一會(huì)回頭還有來(lái)理解
     */
    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;
    }
 
    //重寫(xiě)toString, 便于輸出邊信息
    @Override
    public String toString() {
        return "EData [<" + start + ", " + end + ">= " + weight + "]";
    }
 
 
}

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

相關(guān)文章

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

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

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

    Java?Timer使用講解

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

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

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

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

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

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

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

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

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

    Java線程中斷機(jī)制interrupt、isInterrupted、interrupted方法詳解

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

    Java 限制子類訪問(wèn)的方法分析

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

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

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

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

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

最新評(píng)論