數據結構圖之二(最小生成樹--克魯斯卡爾算法)


【1】克魯斯卡爾算法

普里姆算法是以某頂點為起點,逐步找各頂點上最小權值的邊來構建最小生成樹。

克魯斯卡爾算法是直接以邊為目標去構建。

因為權值是在邊上,直接去找最小權值的邊來構建生成樹也是很自然的想法,只不過構建時要考慮是否會形成環路而已。

此時我們用到了圖的存儲結構中的邊集數組結構。

以下是邊集數組結構的定義代碼:

本算法所用同普里姆算法的實例,我們直接創建圖的邊集數組。

並對邊的權值從小到大排序后如下圖:

【2】克魯斯卡爾算法及詳解

克魯斯卡爾算法及其詳解:

鑒於此算法很簡單,當 i=0, i=1, i=2時執行結果可以眼觀,不再贅述。直接分析重點:

此算法的Find函數由邊數e決定,時間復雜度為O(loge),而外面有一個for循環e次。

所以克魯斯卡爾算法的時間復雜度為O(eloge)

對比兩個算法:

克魯斯卡爾算法主要針對邊展開,邊數少時效率會很高,所以對於稀疏圖有優勢

而普利姆算法對於稠密圖,即邊數非常多的情況會好些。

【3】克魯斯卡爾算法實現

實現代碼如下:

  1 #include <iostream>
  2 using namespace std;
  3 
  4 #define    MAXVER  9
  5 #define MAXEDGE 15
  6 
  7 typedef struct Node
  8 {
  9     int begin;        // 起點
 10     int weight;     // 權值
 11     int end;        // 末點
 12 } edgeNode;
 13 
 14 class Graph
 15 {
 16 private:
 17     edgeNode edge[MAXEDGE];
 18 public:
 19     Graph()
 20     {
 21         for (int i = 0; i < MAXEDGE; ++i)
 22         {
 23             edge[i].begin = edge[i].weight = edge[i].end = 0;
 24         }
 25     }
 26     ~Graph()
 27     {}
 28 
 29 public:
 30     void InsertSort()
 31     {
 32        for (int i = 0; i < MAXEDGE- 1; ++i)
 33        {
 34             if (edge[i+1].weight < edge[i].weight)
 35             {
 36                  Node temp = edge[i+1];
 37                  int j = i + 1;
 38                  do
 39                  {
 40                      edge[j] = edge[j-1];
 41                      --j;
 42                  } while(j >= 0 && edge[j].weight > temp.weight);
 43                                 
 44                  edge[j+1] = temp;
 45             }
 46         }
 47     }
 48 
 49     istream & operator>>(istream &in)
 50     {
 51         int begin, value, end;
 52         cout << "請輸入15條邊的起點 終點 權值:" << endl;
 53         for (int i = 0; i < MAXEDGE; ++i)
 54         {
 55             in >> begin >> end >> value;
 56             edge[i].begin = begin;
 57             edge[i].weight = value;
 58             edge[i].end = end;
 59         }
 60         return in;
 61     }
 62     ostream & operator<<(ostream &out)
 63     {
 64         // 插入排序
 65         InsertSort();
 66         out << "輸出排序邊權值后信息:" << endl;
 67         for (int i = 0; i < MAXEDGE; ++i)
 68         {
 69             out << "edge[" << i << "] " << edge[i].begin << "  " << edge[i].weight << " " << edge[i].end << endl;
 70         }
 71         return out;
 72     }
 73     // 克魯斯卡爾算法
 74     void MiniSpanTree_Kruskal()
 75     {
 76         int i = 0, n = 0, m = 0;
 77         int parent[MAXVER];
 78         for ( ; i < MAXVER; ++i)
 79             parent[i] = 0;
 80         for (i = 0; i < MAXEDGE; ++i)
 81         {
 82             n = Find(parent, edge[i].begin);
 83             m = Find(parent, edge[i].end);
 84             if (n != m)
 85             {
 86                 parent[n] = m;
 87                 cout << " " << edge[i].begin << " " << edge[i].end << " " << edge[i].weight << endl;
 88             }
 89         }
 90     }
 91 
 92     int Find(int *parent, int f)
 93     {
 94         while (parent[f] > 0)
 95             f = parent[f];
 96         return f;
 97     }
 98 };
 99 
100 istream & operator>>(istream &in, Graph &g)
101 {
102     g >> in;
103     return in;
104 }
105 
106 ostream & operator<<(ostream &out, Graph &g)
107 {
108     g << out;
109     return out;
110 }
111 
112 void main()
113 {
114     Graph myg;
115     cin >> myg;
116     cout << myg;
117     myg.MiniSpanTree_Kruskal();
118 }
119  // 備注:
120  // 最小生成樹克魯斯卡爾算法實現
121  // 整理於2013-12-04
122  // 測試需要輸入:
123  /*
124  起始   終點   權值
125  0 1 10
126  0 5 11
127  1 2 18
128  1 8 12
129  1 6 16
130  2 8 8
131  2 3 22
132  3 8 21
133  3 6 24
134  3 7 16
135  3 4 20
136  4 7 7
137  4 5 26
138  5 6 17
139  6 7 19
140   */
View Code

 

Good  Good  Study, Day  Day  Up.

順序  選擇  循環  總結


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM