資料結構:最小產生樹--Kruskal演算法

來源:互聯網
上載者:User

標籤:article   prim   父節點   span   ***   int   algo   bsp   type   

                           Kruskal演算法

Kruskal演算法

    求解最小產生樹的還有一種常見演算法是Kruskal演算法。它比Prim演算法更直觀。從直觀上看,Kruskal演算法的做法是:每次都從剩餘邊中選取權值最小的,當然,這條邊不能使已有的邊產生迴路。

手動求解會發現Kruskal演算法異常簡單,以下是一個範例


先對邊的權值排個序:1(0,1) 2(2,6) 4(1,3) 6(1,2) 8(3,6) 10(5,6) 12(3,5) 15(4,5) 20(0,1)

首選邊1(0,1)、2(2,6)、4(1,3)、6(1,2),此時的圖是這樣



顯然,若選取邊8(3,6)會出現環,則必須拋棄8(3,6),選擇下一條10(5,6)沒有問題。此時圖變成這樣



顯然,12(3,5)相同不可取,選取15(4,5),邊數已達到要求,演算法結束。終於的圖是這種



演算法邏輯人非常easy理解。但用代碼推斷當前邊是否會引起環的出現。則非常棘手。

演算法說明

    為了推斷環的出現,我們換個角度來理解Kruskal演算法的做法:初始時,把圖中的n個頂點看成是獨立的n個連通分量,從樹的角度看,也是n個根節點。我們選邊的標準是這種:若邊上的兩個頂點從屬於兩個不同的連通分量。則此邊可取,否則考察下一條權值最小的邊。

    於是問題又來了,怎樣推斷兩個頂點是否屬於同一個連通分量呢?這個能夠參照並查集的做法解決。它的思路是:假設兩個頂點的根節點是一樣的,則顯然是屬於同一個連通分量。

這也相同暗示著:在增加新邊時,要更新父節點。

詳細細節看代碼:

代碼

#include<iostream> #include<algorithm>using namespace std;#define MAXWEIGHT 100/*全域變數numV頂點數numE邊數*/int numV, numE;//邊typedef struct edge_tag{int tail;int head;int weight;}Edge;//檢測邊bool checkEdge(int tail, int head, int weight){if (tail == head|| tail < 0 || tail >= numV|| head < 0 || head >= numV|| weight <= 0 || weight >= MAXWEIGHT)return false;return true;}//輸入邊void inputEdge(Edge *edge, int numE){int i, tail, head, weight;cout << "輸入邊的起點、終點和權值" << endl;i = 0;while (i < numE){cin >> tail >> head >> weight;while (!checkEdge(tail, head, weight)){cout << "輸入錯誤!又一次輸入" << endl;cin >> tail >> head >> weight;}edge[i].tail = tail;edge[i].head = head;edge[i].weight = weight;i++;}}int cmp(const void *edge1, const void *edge2){return ((Edge*)edge1)->weight - ((Edge*)edge2)->weight;}//並查集的常見操作/*壓縮尋找尋找child的根節點*/int Find(int child, int *parent){if (parent[child] == child)return child;parent[child] = Find(parent[child], parent); //壓縮路徑return parent[child];}//合并bool Union(Edge *e, int *parent, int *childs){//處於同一個棵樹中。則不能合并。否則會出現環int root1, root2;root1 = Find(e->tail, parent);root2 = Find(e->head, parent);if (root1 != root2){//把小樹合并到大樹根下if (childs[root1] > childs[root2]){parent[root2] = root1;childs[root1] += childs[root2] + 1;}else{parent[root1] = root2;childs[root2] += childs[root2] + 1;}return true;}return false;}/*Kruskal演算法求最小產生樹*/void Kruskal(int numV, int numE){//邊的集合Edge *edge = new Edge[numE];inputEdge(edge, numE);/*parent[i]是頂點i的父頂點childs[i]是頂點i的孩子數child的複數是children,這裡的childs是杜撰的*/int *parent = new int[numV];int *childs = new int[numV];//初始化for (int i = 0; i < numV; i++){/*初始時。每個頂點都是根。且無孩子把每個頂點的的父節點設定為自身下標,也是標明類別*/parent[i] = i;childs[i] = 0;}//對邊按權值進行從小到大排序qsort(edge, numE, sizeof(Edge), cmp);int i, count;i = count = 0;cout << "最小產生樹的邊..." << endl;while (i < numE){if (Union(&edge[i], parent, childs)){cout << edge[i].tail << "---" << edge[i].head << endl;count++;}if (count == numV - 1)  //邊數達到要求break;i++;}if (count != numV - 1)cout << "此圖為非連通圖!

無法構成最小產生樹。" << endl;delete[]edge;delete[]parent;delete[]childs;}//檢測頂點數和邊數bool checkVE(int numV, int numE){if (numV <= 0 || numE <= 0 || numE > numV*(numV - 1) / 2)return false;return true;}int main(){cout << "******Kruskal***by David***" << endl;cout << "輸入頂點數、邊數 ";cin >> numV >> numE;while (!checkVE(numV, numE)){cout << "輸入資料有問題!又一次輸入 ";cin >> numV >> numE;}cout << endl << "Kruskal..." << endl;Kruskal(numV, numE);system("pause");return 0;}

執行





轉載請註明出處,本文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/38414683


若有所協助,頂一個哦。


專欄檔案夾:

  • 資料結構與演算法檔案夾 
  • c指標



資料結構:最小產生樹--Kruskal演算法

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.