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

Java圖論進(jìn)階之最小生成樹算法詳解

 更新時(shí)間:2023年01月10日 12:38:23   作者:Node_Hao  
最小生成樹(Minimum Spanning Tree)就是給定無向圖中,邊權(quán)重最小的生成樹,下面這篇文章主要給大家介紹了關(guān)于Java圖論進(jìn)階之最小生成樹算法的相關(guān)資料,文中通過圖文以及實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

1. 最小生成樹

連通圖中的每一棵生成樹 , 都是原圖的極大無環(huán)子圖 , 即: 從中刪去任何一條邊 , 生成樹就不再連通;反之 , 在其中引入任何一條新邊 , 都會(huì)形成一條回路.

若連通圖由n個(gè)頂點(diǎn)組成 , 則其生成樹必含n個(gè)頂點(diǎn)和n-1條邊 , 因此構(gòu)造最小生成樹有三個(gè)準(zhǔn)則:

  • 1.只能使用圖中的邊來構(gòu)造最小生成樹
  • 2.只能使用恰好n-1條邊來連接圖中的n個(gè)頂點(diǎn)
  • 3.選用的n-1條邊不能構(gòu)成回路 

常見求解最小生成樹的算法有: Kruskal算法和Prime算法.兩種算法都采用逐步求解的貪心策略.

貪心算法: 通過局部最優(yōu)解來推出全局最優(yōu)解.

1.1 Kruskal(克魯斯卡爾) 算法

給定一個(gè)有n個(gè)頂點(diǎn)的連通網(wǎng)絡(luò)N={V,E}

首先構(gòu)造一個(gè)由這n個(gè)頂點(diǎn)組成 , 不含任何邊的圖G={V,NULL}.

其次不斷從E中取出權(quán)值最小的一條邊(若有多條任選其一) , 若該邊的兩個(gè)頂點(diǎn)來自不同的連通分量 , 則將此邊加入到G中.

如此反復(fù) , 直到G中邊數(shù)達(dá)到頂點(diǎn)數(shù)-1為止.

核心: 每次迭代時(shí) , 選出權(quán)值最小且兩端點(diǎn)不在同一連通分量上的邊 , 加入生成樹.

步驟分析:

1.由于該算法的思想是全局貪心 , 因此將所有圖中所有邊全部放入優(yōu)先級(jí)隊(duì)列中.
2.構(gòu)造一個(gè)最小生成樹 , 將優(yōu)先級(jí)隊(duì)列中的邊依次加入.
3.為了防止出現(xiàn)環(huán) , 使用并查集判斷每次取出的邊的頂點(diǎn)是否來自同一個(gè)集合 .
4.如果不是同一集合 , 將該邊加入最小生成樹并用并查集將該邊的領(lǐng)接頂點(diǎn)放入同一個(gè)       集合.

代碼示例: 

 /**
     * 克魯斯卡爾算法實(shí)現(xiàn)
     * @param minTree
     * @return
     */
    /**
     * 模擬實(shí)現(xiàn)一條邊
     */
    static class Edge{
        public int srcIndex;
        public int destIndex;
        public int weight;
 
        public Edge(int srcIndex, int destIndex, int weight) {
            this.srcIndex = srcIndex;
            this.destIndex = destIndex;
            this.weight = weight;
        }
    }
 
    public int kruskal(GraphOfMatrix minTree) {
        //1.定義一個(gè)優(yōu)先級(jí)隊(duì)列
        PriorityQueue<Edge> minQ = new PriorityQueue<Edge>(new Comparator<Edge>() {
            @Override
            public int compare(Edge o1, Edge o2) {
                return o1.weight - o2.weight;
            }
        });
        int n = arrayV.length;
        //2.遍歷領(lǐng)接矩陣,將所有的邊都放入優(yōu)先級(jí)隊(duì)列中
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (i < j && Matrix[i][j] != Integer.MIN_VALUE) {
                    minQ.offer(new Edge(i, j, Matrix[i][j]));
                }
            }
        }
        //3.構(gòu)造并查集將符合要求的邊加入到最小生成樹中
        UnionFindSet ufs = new UnionFindSet(n);
 
        int size = 0;//記錄最小生成樹中邊的數(shù)量
        int totalWeight = 0;//記錄權(quán)值
        while (size < n - 1 && !minQ.isEmpty()) {
            Edge edge = minQ.poll();
            int srcIndex = edge.srcIndex;
            int destIndex = edge.destIndex;
            //同一邊的相鄰頂點(diǎn)不能來自同一集合
            if (!ufs.isSameUnionFindSet(srcIndex, destIndex)) {
                //將符合條件的邊加入到最小生成樹中
                minTree.addEdgeUseIndex(srcIndex, destIndex, Matrix[srcIndex][destIndex]);
                System.out.println("選擇的邊"+arrayV[srcIndex]+" -> "+arrayV[destIndex]+Matrix[srcIndex][destIndex]);
                size++;
                totalWeight += Matrix[srcIndex][destIndex];
                //將添加過的邊的相鄰頂點(diǎn)放入同一集合,防止出現(xiàn)環(huán).
                ufs.union(srcIndex, destIndex);
            }
        }
        if (size == n - 1) {
            return totalWeight;
        } else {
            throw new RuntimeException("沒有最小生成樹");
        }
    }
 
   //按照下標(biāo)將邊加入到最小生成樹中
    public void addEdgeUseIndex(int srcIndex,int destIndex,int weight){
        Matrix[srcIndex][destIndex] = weight;
        //如果是無向圖鄰接矩陣對(duì)稱位置也要添加
        if (!isDirect){
            Matrix[destIndex][srcIndex] = weight;
        }
    }
    //測(cè)試克魯斯卡爾算法
    public static void main(String[] args) {
        String str = "abcdefghi";
        char[] array =str.toCharArray();
        graph.GraphOfMatrix g = new graph.GraphOfMatrix(str.length(),false);
        g.initArray(array);
        g.addEdge('a', 'b', 4);
        g.addEdge('a', 'h', 8);
//g.addEdge('a', 'h', 9);
        g.addEdge('b', 'c', 8);
        g.addEdge('b', 'h', 11);
        g.addEdge('c', 'i', 2);
        g.addEdge('c', 'f', 4);
        g.addEdge('c', 'd', 7);
        g.addEdge('d', 'f', 14);
        g.addEdge('d', 'e', 9);
        g.addEdge('e', 'f', 10);
        g.addEdge('f', 'g', 2);
        g.addEdge('g', 'h', 1);
        g.addEdge('g', 'i', 6);
        g.addEdge('h', 'i', 7);
        graph.GraphOfMatrix kminTree = new graph.GraphOfMatrix(str.length(),false);
        System.out.println(g.kruskal(kminTree));
        kminTree.printGraph();
    }

構(gòu)造并查集:

public class UnionFindSet {
    public int[] elem;
 
    public UnionFindSet(int n){
        this.elem = new int[n];
        Arrays.fill(elem,-1);
    }
 
    /**
     * 查找數(shù)據(jù)x的根節(jié)點(diǎn)
     * @param x
     * @return
     */
    public int findRoot(int x){
        if (x < 0){
            throw new RuntimeException("下表不合法");
        }
        while (elem[x] >= 0){
            x = elem[x];
        }
        return x;
    }
    /**
     * 查詢x1和x2是不是同一個(gè)集合
     * @param x1
     * @param x2
     * @return
     */
    public boolean isSameUnionFindSet(int x1 , int x2){
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if (index1 == index2){
            return true;
        }
        return false;
    }
 
    /**
     * 這是合并操作
     * @param x1
     * @param x2
     */
    public void union(int x1 , int x2){
        int index1 = findRoot(x1);
        int index2 = findRoot(x2);
        if (index1 == index2) return;
        elem[index1] = elem[index1] + elem[index2];
        elem[index2] = index1;
    }
 
    /**
     * 有幾對(duì)關(guān)系
     * @return
     */
    public int getCount(){
        int count = 0;
        for (int x:elem) {
            if (x < 0){
                count++;
            }
        }
        return count;
    }
    public void Print(){
        for (int x:elem){
            System.out.print(x+" ");
        }
        System.out.println();
    }
}

 測(cè)試結(jié)果:

1.2 Prime(普里姆) 算法

普里姆算法與克魯斯卡爾算法類似 , 核心區(qū)別是普里姆算法采用局部貪心的思想.

首先 , 設(shè)定兩個(gè)集合 , X{}已確定頂點(diǎn)的集合 , Y{}未確定頂點(diǎn)的集合.

其次 , 假設(shè)圖中的頂點(diǎn)為 a,b,c,d,e,f,g,h,i.放入Y{}中.

然后 , 任取一個(gè)頂點(diǎn)放入X{}中 . 在Y{}中選擇一個(gè)與該頂點(diǎn)相連權(quán)值最小的邊 , 加入最小生成樹中.

如此重復(fù) , 直到最小生成樹的邊數(shù)達(dá)到頂點(diǎn)數(shù)-1為止.

代碼示例:

/**
     * 普里姆算法實(shí)現(xiàn)
     * @param minTree
     * @param chV 圖中頂點(diǎn)的起點(diǎn)
     * @return
     */
    public int prime(GraphOfMatrix minTree,char chV) {
        int srcIndex = getIndexOfV(chV);
        //存儲(chǔ)已確定的頂點(diǎn)
        Set<Integer> setX = new HashSet<>();
        setX.add(srcIndex);
        //初始化未確定的點(diǎn)
        Set<Integer> setY = new HashSet<>();
        int n = arrayV.length;
        for (int i = 0; i < n; i++) {
            if (i != srcIndex){
                setY.add(i);
            }
        }
        //定義一個(gè)優(yōu)先級(jí)隊(duì)列
        PriorityQueue<Edge> minQ = new PriorityQueue<>(new Comparator<Edge>() {
            @Override
            public int compare(Edge o1, Edge o2) {
                return o1.weight - o2.weight;
            }
        });
        //遍歷srcIndex連接出去的邊,并放入優(yōu)先級(jí)隊(duì)列中排序
        for (int i = 0; i < n; i++) {
            if (Matrix[srcIndex][i] != Integer.MIN_VALUE){
                minQ.offer(new Edge(srcIndex,i,Matrix[srcIndex][i]));
            }
        }
        int size = 0;
        int totalWeight = 0;
        while (!minQ.isEmpty()){
            Edge min = minQ.poll();
            int srcI = min.srcIndex;
            int destI = min.destIndex;
            if (setX.contains(destI)){
                //此時(shí)會(huì)構(gòu)成環(huán)
            }else {
                minTree.addEdgeUseIndex(srcI,destI,Matrix[srcI][destI]);
                System.out.println("起點(diǎn)"+arrayV[srcI]+" -> "+"終點(diǎn)"+arrayV[destI]+Matrix[srcI][destI]);
                size++;
                totalWeight+=min.weight;
                if (size == n-1){
                    return totalWeight;
                }
                //更新兩個(gè)集合
                setX.add(destI);
                setY.remove(destI);
                //把dest連出去的所有邊也放到優(yōu)先級(jí)隊(duì)列中
                for (int i = 0; i < n; i++) {
                    if (Matrix[destI][i] != Integer.MIN_VALUE && !setX.contains(i)){
                        minQ.offer(new Edge(destI,i,Matrix[destI][i]));
                    }
                }
            }
        }
       throw new RuntimeException("沒有最小生成樹");
    }
    //測(cè)試普里姆算法
    public static void main3(String[] args) {
            String str = "abcdefghi";
            char[] array =str.toCharArray();
            GraphOfMatrix g = new GraphOfMatrix(str.length(),false);
            g.initArray(array);
            g.addEdge('a', 'b', 4);
            g.addEdge('a', 'h', 8);
//g.addEdge('a', 'h', 9);
            g.addEdge('b', 'c', 8);
            g.addEdge('b', 'h', 11);
            g.addEdge('c', 'i', 2);
            g.addEdge('c', 'f', 4);
            g.addEdge('c', 'd', 7);
            g.addEdge('d', 'f', 14);
            g.addEdge('d', 'e', 9);
            g.addEdge('e', 'f', 10);
            g.addEdge('f', 'g', 2);
            g.addEdge('g', 'h', 1);
            g.addEdge('g', 'i', 6);
            g.addEdge('h', 'i', 7);
            GraphOfMatrix primTree = new GraphOfMatrix(str.length(),false);
            System.out.println(g.prime(primTree,'a'));
            primTree.printGraph();
    }

總結(jié)

到此這篇關(guān)于Java圖論進(jìn)階之最小生成樹算法的文章就介紹到這了,更多相關(guān)Java最小生成樹算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java因項(xiàng)目配置不當(dāng)而引發(fā)的數(shù)據(jù)泄露

    Java因項(xiàng)目配置不當(dāng)而引發(fā)的數(shù)據(jù)泄露

    這篇文章主要介紹了Java因項(xiàng)目配置不當(dāng)而引發(fā)的數(shù)據(jù)泄露解決辦法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • Java不帶break將導(dǎo)致case穿透問題

    Java不帶break將導(dǎo)致case穿透問題

    這篇文章主要介紹了Java不帶break將導(dǎo)致case穿透問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • 5分鐘搞定java單例模式

    5分鐘搞定java單例模式

    單例模式(Singleton?Pattern)是?Java?中最簡(jiǎn)單的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式,本文給大家介紹下java單例模式的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2022-03-03
  • Java--SSH,SSM和Spring?Boot框架區(qū)別及優(yōu)缺點(diǎn)說明

    Java--SSH,SSM和Spring?Boot框架區(qū)別及優(yōu)缺點(diǎn)說明

    這篇文章主要介紹了Java--SSH,SSM和Spring?Boot框架區(qū)別及優(yōu)缺點(diǎn)說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • JAVA 多線程之信號(hào)量(Semaphore)實(shí)例詳解

    JAVA 多線程之信號(hào)量(Semaphore)實(shí)例詳解

    這篇文章主要介紹了JAVA 多線程之信號(hào)量(Semaphore)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • Java設(shè)計(jì)模式之工廠模式案例詳解

    Java設(shè)計(jì)模式之工廠模式案例詳解

    工廠模式(Factory Pattern)是Java中最常用的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。本文將通過案例詳細(xì)講解一下工廠模式,需要的可以參考一下
    2022-02-02
  • Java中的@PreAuthorize注解使用詳解

    Java中的@PreAuthorize注解使用詳解

    這篇文章主要介紹了Java中的@PreAuthorize注解使用詳解,@PreAuthorize注解會(huì)在方法執(zhí)行前進(jìn)行權(quán)限驗(yàn)證,支持Spring EL表達(dá)式,它是基于方法注解的權(quán)限解決方案,需要的朋友可以參考下
    2023-10-10
  • 解決IDEA創(chuàng)建maven項(xiàng)目時(shí)pom.xml沒有變藍(lán)的問題

    解決IDEA創(chuàng)建maven項(xiàng)目時(shí)pom.xml沒有變藍(lán)的問題

    這篇文章主要介紹了解決IDEA創(chuàng)建maven項(xiàng)目時(shí)pom.xml沒有變藍(lán)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Spring boot route Controller接收參數(shù)常用方法解析

    Spring boot route Controller接收參數(shù)常用方法解析

    這篇文章主要介紹了Spring boot route Controller接收參數(shù)常用方法解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • java自加和自減運(yùn)算過程

    java自加和自減運(yùn)算過程

    這篇文章主要介紹了java自加和自減運(yùn)算過程,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-03-03

最新評(píng)論

日照市| 大石桥市| 莱州市| 乌拉特前旗| 腾冲县| 梁河县| 余庆县| 腾冲县| 卢龙县| 奉贤区| 耒阳市| 遂溪县| 凤台县| 天等县| 石渠县| 米脂县| 柳州市| 阿尔山市| 青龙| 泗洪县| 沁源县| 嘉义市| 崇仁县| 永济市| 临猗县| 垫江县| 阿坝| 巴彦县| 曲松县| 海南省| 林口县| 琼中| 河北省| 汽车| 腾冲县| 获嘉县| 蓬溪县| 晋城| 临泉县| 湄潭县| 乌兰县|