最小生成樹

最小生成樹要求:

首先躲履,保證所有點連通见间,其次保證邊的權(quán)重和最低
應用范圍:無向圖

Kruskal(克魯斯卡爾)算法:

思路:

依次找權(quán)值最小的邊,直到遍歷完邊并且不形成環(huán)為止工猜。
實現(xiàn)方法用的并查集缤剧,首先把圖的所有變放到一個小根堆里,然后從小根堆poll域慷,判斷poll出的邊edge的fromNode和toNode在不在并查集里,即他們的父節(jié)點是不是一樣的汗销,如果一樣就說明形成環(huán)了犹褒,如果沒有就把這兩個點加入到并查集合里,執(zhí)行直到小根堆為空

代碼:

    public static class UnionFind {
                //key 當前結(jié)點 value 父節(jié)點
        private HashMap<Node, Node> fatherMap;
                //當前集合的大谐谡搿(最后就用頭節(jié)點的大小來表示叠骑,size存在頭節(jié)點中)
        private HashMap<Node, Integer> rankMap;

        public UnionFind() {
            fatherMap = new HashMap<Node, Node>();
            rankMap = new HashMap<Node, Integer>();
        }

        private Node findFather(Node n) {
            Node father = fatherMap.get(n);
            if (father != n) {
                father = findFather(father);
            }
            fatherMap.put(n, father);
            return father;
        }

        public void makeSets(Collection<Node> nodes) {
            fatherMap.clear();
            rankMap.clear();
            for (Node node : nodes) {
                fatherMap.put(node, node);
                rankMap.put(node, 1);
            }
        }

        public boolean isSameSet(Node a, Node b) {
            return findFather(a) == findFather(b);
        }

        public void union(Node a, Node b) {
            if (a == null || b == null) {
                return;
            }
            Node aFather = findFather(a);
            Node bFather = findFather(b);
            if (aFather != bFather) {
                int aFrank = rankMap.get(aFather);
                int bFrank = rankMap.get(bFather);
                if (aFrank <= bFrank) {
                    fatherMap.put(aFather, bFather);
                    rankMap.put(bFather, aFrank + bFrank);
                } else {
                    fatherMap.put(bFather, aFather);
                    rankMap.put(aFather, aFrank + bFrank);
                }
            }
        }
    }

    public static class EdgeComparator implements Comparator<Edge> {

        @Override
        public int compare(Edge o1, Edge o2) {
            return o1.weight - o2.weight;
        }

    }

    public static Set<Edge> kruskalMST(Graph graph) {
        UnionFind unionFind = new UnionFind();
        unionFind.makeSets(graph.nodes.values());
        PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new EdgeComparator());
        for (Edge edge : graph.edges) {
            priorityQueue.add(edge);
        }
        Set<Edge> result = new HashSet<>();
        while (!priorityQueue.isEmpty()) {
            Edge edge = priorityQueue.poll();
            if (!unionFind.isSameSet(edge.from, edge.to)) {
                result.add(edge);
                unionFind.union(edge.from, edge.to);
            }
        }
        return result;
    }

Prim(普里姆)算法:

思路:

創(chuàng)建一個優(yōu)先級隊列(小根堆),創(chuàng)建一個Hashset set用來存已經(jīng)經(jīng)過的節(jié)點削茁,再創(chuàng)建一個Set result 來存結(jié)果邊宙枷,從所有節(jié)點中隨機選一個節(jié)點,判斷該節(jié)點是否在set里茧跋,如果不在就加入慰丛,然后把當前node的所有的邊加入到優(yōu)先級隊列,然后彈出小根堆的堆頂瘾杭,即當前節(jié)點所連邊權(quán)值最小的那一條诅病,然后判斷這條邊所連的節(jié)點toNode,是否在set中如果不在粥烁,就加入贤笆,同時把邊加入到result中,然后再把toNode所連的所有邊加入到優(yōu)先級隊列(小根堆里)讨阻,依次執(zhí)行下去芥永,得出結(jié)果。
總結(jié)起來一句話:隨機找一個節(jié)點钝吮,通過這個節(jié)點找權(quán)值最小的邊埋涧,通過這條邊再找節(jié)點板辽,節(jié)點如果沒遍歷,就繼續(xù)從這個節(jié)點找權(quán)值最小的邊飞袋,最后結(jié)束戳气。

代碼:

    public static class EdgeComparator implements Comparator<Edge> {

        @Override
        public int compare(Edge o1, Edge o2) {
            return o1.weight - o2.weight;
        }

    }

    public static Set<Edge> primMST(Graph graph) {
        PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new EdgeComparator());
        HashSet<Node> set = new HashSet<>();
        Set<Edge> result = new HashSet<>();
        for (Node node : graph.nodes.values()) {
            if (!set.contains(node)) {
                set.add(node);
                for (Edge edge : node.edges) {
                    priorityQueue.add(edge);
                }
                while (!priorityQueue.isEmpty()) {
                    Edge edge = priorityQueue.poll();
                    Node toNode = edge.to;
                    if (!set.contains(toNode)) {
                        set.add(toNode);
                        result.add(edge);
                        for (Edge nextEdge : toNode.edges) {
                            priorityQueue.add(nextEdge);
                        }
                    }
                }
            }
        }
        return result;
    }

注意:代碼上的最開始的超級循環(huán)是用來處理森林的問題,比如一個圖有森林(森林:n棵互不相交的樹)巧鸭,你第一次選的起始點遍歷完后瓶您,就只能處理一棵樹,第二棵沒有處理纲仍,所以這時候遍歷所有節(jié)點結(jié)合判斷set里是否有遍歷的當前node呀袱,即可完成所有樹的最小生成樹的查找。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末郑叠,一起剝皮案震驚了整個濱河市夜赵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乡革,老刑警劉巖寇僧,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異沸版,居然都是意外死亡嘁傀,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門视粮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來细办,“玉大人,你說我怎么就攤上這事蕾殴⌒ψ玻” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵钓觉,是天一觀的道長茴肥。 經(jīng)常有香客問我,道長议谷,這世上最難降的妖魔是什么炉爆? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮卧晓,結(jié)果婚禮上芬首,老公的妹妹穿的比我還像新娘。我一直安慰自己逼裆,他們只是感情好郁稍,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著胜宇,像睡著了一般耀怜。 火紅的嫁衣襯著肌膚如雪恢着。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天财破,我揣著相機與錄音掰派,去河邊找鬼。 笑死左痢,一個胖子當著我的面吹牛靡羡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播俊性,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼略步,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了定页?” 一聲冷哼從身側(cè)響起趟薄,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎典徊,沒想到半個月后杭煎,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡卒落,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年岔帽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片导绷。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖屎飘,靈堂內(nèi)的尸體忽然破棺而出妥曲,到底是詐尸還是另有隱情,我是刑警寧澤钦购,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布檐盟,位于F島的核電站,受9級特大地震影響押桃,放射性物質(zhì)發(fā)生泄漏葵萎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一唱凯、第九天 我趴在偏房一處隱蔽的房頂上張望羡忘。 院中可真熱鬧,春花似錦磕昼、人聲如沸卷雕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽漫雕。三九已至滨嘱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間浸间,已是汗流浹背太雨。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留魁蒜,地道東北人囊扳。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像梅惯,于是被迫代替她去往敵國和親宪拥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容