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

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

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

一、prim算法

時間復雜度較之kruskal較高

通俗的解釋就是:

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

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

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

綜合以上三點就是我們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;
        //鄰接矩陣的關系使用二維數(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++) {//遍歷沒有訪問過的點
                        //在未訪問點中尋找所有與訪問過的點相連的邊中權值最小值
                        if (visited[i] == 1 && visited[j] == 0 && graph.weight[i][j] < minWeight) {
                            minWeight = graph.weight[i][j];
                            h1 = i;
                            h2 = j;
                        }
                    }
                }
            }
            sum += minWeight; // 求最小生成熟的總權值
            //此時已經(jīng)找到一條邊是最小了
            System.out.println("邊<" + graph.data[h1] + "," + graph.data[h2] + "> 權值:" + minWeight);
            //然后標記點
            visited[h2] = 1;
            //將權值重新變成最大值
            minWeight = 10000;
        }
        System.out.println("最小生成樹的權值是:" + 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算法

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

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

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

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

(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}};
        //大家可以在去測試其它的鄰接矩陣,結果都可以得到最小生成樹.
 
        //創(chuàng)建KruskalCase 對象實例
        KruskalCase kruskalCase = new KruskalCase(vertexs, matrix);
        //輸出構建的
        kruskalCase.print();
        kruskalCase.kruskal();
 
    }
 
    //構造器
    public KruskalCase(char[] vertexs, int[][] matrix) {
        //初始化頂點數(shù)和邊的個數(shù)
        int vlen = vertexs.length;
 
        //初始化頂點, 復制拷貝的方式
        this.vertexs = new char[vlen];
        for (int i = 0; i < vertexs.length; i++) {
            this.vertexs[i] = vertexs[i];
        }
 
        //初始化邊, 使用的是復制拷貝的方式
        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; //表示最后結果數(shù)組的索引
        int[] ends = new int[edgeNum]; //用于保存"已有最小生成樹" 中的每個頂點在最小生成樹中的終點
        //創(chuàng)建結果數(shù)組, 保存最后的最小生成樹
        EData[] rets = new EData[edgeNum];
 
        //獲取圖中 所有的邊的集合 , 一共有12邊
        EData[] edges = getEdges();
        System.out.println("圖的邊的集合=" + Arrays.toString(edges) + " 共" + edges.length); //12
 
        //按照邊的權值大小進行排序(從小到大)
        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
            //是否構成回路
            if (m != n) { //沒有構成回路
                ends[m] = n; // 設置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頂點對應的下標,如果找不到,返回-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ù)組就是記錄了各個頂點對應的終點是哪個,ends 數(shù)組是在遍歷過程中,逐步形成
     * @param i    : 表示傳入的頂點對應的下標
     * @return 返回的就是 下標為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)建一個類EData ,它的對象實例就表示一條邊
class EData {
    char start; //邊的一個點
    char end; //邊的另外一個點
    int weight; //邊的權值
 
    //構造器
    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 + "]";
    }
 
 
}

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

相關文章

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

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

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

    Java中常用的設計模式之觀察者模式詳解

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

    java模擬http的Get/Post請求,并設置ip與port代理的方法

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

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

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

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

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

    使用@SpringBootTest注解進行單元測試

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

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

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

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

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

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

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

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

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

最新評論

延边| 石台县| 云梦县| 平度市| 嘉定区| 中西区| 崇礼县| 南漳县| 隆化县| 靖远县| 云安县| 武川县| 滦南县| 石城县| 文化| 井研县| 大名县| 天祝| 上高县| 东阿县| 梧州市| 荣成市| 盐津县| 丹寨县| 永仁县| 富蕴县| 呼图壁县| 宜宾县| 台北县| 靖安县| 光泽县| 聂拉木县| 上饶市| 东阳市| 若羌县| 勃利县| 娱乐| 河南省| 太白县| 翁源县| 安新县|