最小生成樹(二)

** Prim算法 **
Prim算法的每一步都會為一棵生長中的樹添加一條邊够庙。一開始這棵樹只有一個頂點,然后會向它添加V-1條邊笙僚,每次總是將下一條連接樹中的頂點與不在樹中的頂點且權(quán)重最小的邊加入樹中。
1.Prim算法的延時實現(xiàn):
新加入樹中的頂點與其他已經(jīng)在樹中頂點的所有邊都會失效(這樣的邊不可能是橫切邊),Prim的延時算法會把這些邊先保留桥滨,等到要刪除的時候再檢查有效性。

public class LazyPrimMST{
    private boolean[] marked;            //最小生成樹的頂點
    private Queue<Edge> mst;            //最小生成樹的邊
    private MinPQ<Edge> pq;            //橫切邊(包括已經(jīng)失效的邊)

    
    public LazyPrimMST(EdgeWeightedGraph G){
        pq = new MinPQ<Edge>();
        marked = new boolean[G.V()];
        mst = new Queue<Edge>();

        visit(G, 0);            //假設(shè)G是連通的
        while(!pq.isEmpty()){
            Edge e = pq.delMin();            //從pq中得到權(quán)重最小的邊
            int v = e.either(), w = e.other(v);
            if ( marked[v] && marked[w]) continue;        //跳過失效的邊
            mst.enqueue(e);                             //將邊添加到樹中
            if(!marked[v]) visit(G,v);                   //將頂點添加到樹中     
            if(!marked[v])  visit(G,w);          
        }
    }
    private void visit(EdgeWeightedGraph G, int v){
        //標(biāo)記頂點v并將所有連接v和未標(biāo)記頂點的邊加入pq
        marked[v] = true;
        for(Edge e: G.adj(v))
            if(!marked[e.other(v)])  pq.insert(e);
    }
    public Iterable<Edge> edges(){
        return mst;
    }
    public double weight()    
}     

2.Prim算法的即時實現(xiàn)
要改進之前的算法弛车,我們可以嘗試從優(yōu)先隊列中刪除失效的邊齐媒,這樣優(yōu)先隊列就只含有樹頂點和非樹頂點之間的橫切邊。除此之外纷跛,對于每個非樹頂點w喻括,在把新的樹頂點v添加到樹中時,w到最小生成樹的距離可能更近了贫奠。我們不需要保存所有從w到最小生成樹的邊唬血,而只需要其中最小的那一條——在將v添加到樹中后望蜡,遍歷v鄰接鏈表即可。

public class PrimMST{
    private Edge[] edgeTo;            //距離樹最近的邊
    private double[] distTo;              //distTo[w] = edgeTo[w].weight()
    private boolean[] marked;           //如果v在樹中則為true
    private IndexMinPQ<Double> pq;        //有效的橫切邊

    public PrimMST(EdgeWeightedGraph G){
        edgeTo = new Edge[G.V()];
        distTo = new double[G.V()];
        marked = new boolean[G.V()];
        for(int v = 0; v<G.V(); v++){
            distTo[v] = Double.POSITIVE_INFINITY;
        pq = new IndexMinPQ<Double>(G.V());

        distTo[0] = 0.0;
        pq.insert(0,0.0);          //用頂點和權(quán)重0初始化pq
        while(!pq.isEmpty())
            visit(G, pq.delMin());          //將最近的頂點添加到樹中
    }
    private void visit(EdgeWeightedGraph G, int v){
    //將頂點添加到樹中,更新數(shù)據(jù)
        marked[v] = true;
        for(Edge e:G.adj(v)){
            int w = e.other(v);
            if(marked[w]) continue;      //v-w失效
            if(e.weight() < distTo[w]){
                edgeTo[w] = e;
                distTo[w] = e.weight();
                if(pq.contains(w))  pq.change(w, distTo[w]);
                else   pq.insert(w, distTo[w]);
            }
        }
    }
    public Iterable<Edge> edges() 
    public double weight()
}

** Kruskal算法 **
Kruskal算法的主要思想是按照邊的權(quán)重排序(從小到大)處理他們,將邊加入最小生成樹中韧骗,加入的邊不會與已加入的邊構(gòu)成環(huán)扎附,直到樹中含有V-1條邊為止。
我們將會使用一條優(yōu)先隊列來將邊按照權(quán)重排序,用一個union-find數(shù)據(jù)結(jié)構(gòu)來識別會形成環(huán)的邊,以及一條隊列來保存最小生成樹的所有邊。

public class KruskalMST{
    private Queue<Edge> mst;
    public KruskalMST(EdgeWeightedGraph G){
        mst = new Queue<Edge>();
        MinPQ<Edge> pq = new MinPQ<Edge>();
        for( Edge e:G.edges()) pq.insert(e);
        UF uf = new UF(G.V());
        while( !pq.isEmpty() && mst.size() < G.V() -1){
            Edge e = pq.delMin();          //從pq中得到權(quán)重最小的邊和它的頂點
            int v = e.either(), w = e.other();
            if(uf.connected(v, w))  continue;          //忽略失效的邊
            uf.union(v,w);                    //合并分量
            mst.enqueue(e);              //將得到的邊添加到最小生成樹中
        }
    }
    public Iterable<Edge> edges()
    {     return mst;    }
    public double weight()        
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末微姊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子分预,更是在濱河造成了極大的恐慌柒桑,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件噪舀,死亡現(xiàn)場離奇詭異魁淳,居然都是意外死亡,警方通過查閱死者的電腦和手機与倡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門界逛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人纺座,你說我怎么就攤上這事息拜。” “怎么了净响?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵少欺,是天一觀的道長。 經(jīng)常有香客問我馋贤,道長赞别,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任配乓,我火速辦了婚禮仿滔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘犹芹。我一直安慰自己崎页,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布腰埂。 她就那樣靜靜地躺著飒焦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪屿笼。 梳的紋絲不亂的頭發(fā)上牺荠,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天翁巍,我揣著相機與錄音,去河邊找鬼志电。 笑死,一個胖子當(dāng)著我的面吹牛蛔趴,可吹牛的內(nèi)容都是我干的挑辆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼孝情,長吁一口氣:“原來是場噩夢啊……” “哼鱼蝉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起箫荡,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤魁亦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后羔挡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洁奈,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年绞灼,在試婚紗的時候發(fā)現(xiàn)自己被綠了利术。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡低矮,死狀恐怖印叁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情军掂,我是刑警寧澤轮蜕,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站蝗锥,受9級特大地震影響跃洛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜终议,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一税课、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧痊剖,春花似錦韩玩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至叮贩,卻和暖如春击狮,著一層夾襖步出監(jiān)牢的瞬間佛析,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工彪蓬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留寸莫,地道東北人。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓档冬,卻偏偏與公主長得像膘茎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子酷誓,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355

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