色吊丝最新资源-第一福利在线视频-欧美久久久-欧产日产国产精品v原神 |www.phbaer.net

來古計算機 > 軟件編程 > 正文

計算機經典算法之Kruskal算法

 經典算法之Kruskal算法

一:思想

    若存在M={0,1,2,3,4,5}這樣6個節點,我們知道Prim算法構建生成樹是從”頂點”這個角度來思考的,然后采用“貪心思想”

來一步步擴大化,最后形成整體最優解,而Kruskal算法有點意思,它是站在”邊“這個角度在思考的,首先我有兩個集合。

1. 頂點集合(vertexs):

     比如M集合中的每個元素都可以認為是一個獨根樹(是不是想到了并查集?)。

2.邊集合(edges):

    對圖中的每條邊按照權值大小進行排序。(是不是想到了優先隊列?)

好了,下面該如何操作呢?

首先:我們從edges中選出權值最小的一條邊來作為生成樹的一條邊,然后將該邊的兩個頂點合并為一個新的樹。

然后:我們繼續從edges中選出次小的邊作為生成樹的第二條邊,但是前提就是邊的兩個頂點一定是屬于兩個集合中,如果不是

        則剔除該邊繼續選下一條次小邊。

最后:經過反復操作,當我們發現n個頂點的圖中生成樹已經有n-1邊的時候,此時生成樹構建完畢。

從圖中我們還是很清楚的看到Kruskal算法構建生成樹的詳細過程,同時我們也看到了”并查集“和“優先隊列“這兩個神器

來加速我們的生成樹構建。

 

二:構建

1.Build方法

這里我灌的是一些測試數據,同時在矩陣構建完畢后,將頂點信息放入并查集,同時將邊的信息放入優先隊列,方便我們在

做生成樹的時候秒殺。

 

 1 #region 矩陣的構建
 2         /// <summary>
 3         /// 矩陣的構建
 4         /// </summary>
 5         public void Build()
 6         {
 7             //頂點數
 8             graph.vertexsNum = 6;
 9 
10             //邊數
11             graph.edgesNum = 8;
12 
13             graph.vertexs = new int[graph.vertexsNum];
14 
15             graph.edges = new int[graph.vertexsNum, graph.vertexsNum];
16 
17             //構建二維數組
18             for (int i = 0; i < graph.vertexsNum; i++)
19             {
20                 //頂點
21                 graph.vertexs[i] = i;
22 
23                 for (int j = 0; j < graph.vertexsNum; j++)
24                 {
25                     graph.edges[i, j] = int.MaxValue;
26                 }
27             }
28 
29             graph.edges[0, 1] = graph.edges[1, 0] = 80;
30             graph.edges[0, 3] = graph.edges[3, 0] = 100;
31             graph.edges[0, 5] = graph.edges[5, 0] = 20;
32             graph.edges[1, 2] = graph.edges[2, 1] = 90;
33             graph.edges[2, 5] = graph.edges[5, 2] = 70;
34             graph.edges[4, 5] = graph.edges[5, 4] = 40;
35             graph.edges[3, 4] = graph.edges[4, 3] = 60;
36             graph.edges[2, 3] = graph.edges[3, 2] = 10;
37 
38             //優先隊列,存放樹中的邊
39             queue = new PriorityQueue<Edge>();
40 
41             //并查集
42             set = new DisjointSet<int>(graph.vertexs);
43 
44             //將對角線讀入到優先隊列
45             for (int i = 0; i < graph.vertexsNum; i++)
46             {
47                 for (int j = i; j < graph.vertexsNum; j++)
48                 {
49                     //說明該邊有權重
50                     if (graph.edges[i, j] != int.MaxValue)
51                     {
52                         queue.Eequeue(new Edge()
53                         {
54                             startEdge = i,
55                             endEdge = j,
56                             weight = graph.edges[i, j]
57                         }, graph.edges[i, j]);
58                     }
59                 }
60             }
61         }
62         #endregion

2:Kruskal算法

并查集,優先隊列都有數據了,下面我們只要出隊操作就行了,如果邊的頂點不在一個集合中,我們將其收集作為最小生成樹的一條邊,

按著這樣的方式,最終生成樹構建完畢,怎么樣,組合拳打的爽不爽?

1 #region Kruskal算法
 2         /// <summary>
 3         /// Kruskal算法
 4         /// </summary>
 5         public List<Edge> Kruskal()
 6         {
 7             //最后收集到的最小生成樹的邊
 8             List<Edge> list = new List<Edge>();
 9 
10             //循環隊列
11             while (queue.Count() > 0)
12             {
13                 var edge = queue.Dequeue();
14 
15                 //如果該兩點是同一個集合,則剔除該集合
16                 if (set.IsSameSet(edge.t.startEdge, edge.t.endEdge))
17                     continue;
18 
19                 list.Add(edge.t);
20 
21                 //然后將startEdge 和 endEdge Union起來,表示一個集合
22                 set.Union(edge.t.startEdge, edge.t.endEdge);
23 
24                 //如果n個節點有n-1邊的時候,此時生成樹已經構建完畢,提前退出
25                 if (list.Count == graph.vertexsNum - 1)
26                     break;
27             }
28 
29             return list;
30         }
31         #endregion

最后是總的代碼:


 1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Diagnostics;
  6 using System.Threading;
  7 using System.IO;
  8 using System.Threading.Tasks;
  9 
 10 namespace ConsoleApplication2
 11 {
 12     public class Program
 13     {
 14         public static void Main()
 15         {
 16             MatrixGraph graph = new MatrixGraph();
 17 
 18             graph.Build();
 19 
 20             var edges = graph.Kruskal();
 21 
 22             foreach (var edge in edges)
 23             {
 24                 Console.WriteLine("({0},{1})({2})", edge.startEdge, edge.endEdge, edge.weight);
 25             }
 26 
 27             Console.Read();
 28         }
 29     }
 30 
 31     #region 定義矩陣節點
 32     /// <summary>
 33     /// 定義矩陣節點
 34     /// </summary>
 35     public class MatrixGraph
 36     {
 37         Graph graph = new Graph();
 38 
 39         PriorityQueue<Edge> queue;
 40 
 41         DisjointSet<int> set;
 42 
 43         public class Graph
 44         {
 45             /// <summary>
 46             /// 頂點信息
 47             /// </summary>
 48             public int[] vertexs;
 49 
 50             /// <summary>
 51             /// 邊的條數
 52             /// </summary>
 53             public int[,] edges;
 54 
 55             /// <summary>
 56             /// 頂點個數
 57             /// </summary>
 58             public int vertexsNum;
 59 
 60             /// <summary>
 61             /// 邊的個數
 62             /// </summary>
 63             public int edgesNum;
 64         }
 65 
 66         #region 矩陣的構建
 67         /// <summary>
 68         /// 矩陣的構建
 69         /// </summary>
 70         public void Build()
 71         {
 72             //頂點數
 73             graph.vertexsNum = 6;
 74 
 75             //邊數
 76             graph.edgesNum = 8;
 77 
 78             graph.vertexs = new int[graph.vertexsNum];
 79 
 80             graph.edges = new int[graph.vertexsNum, graph.vertexsNum];
 81 
 82             //構建二維數組
 83             for (int i = 0; i < graph.vertexsNum; i++)
 84             {
 85                 //頂點
 86                 graph.vertexs[i] = i;
 87 
 88                 for (int j = 0; j < graph.vertexsNum; j++)
 89                 {
 90                     graph.edges[i, j] = int.MaxValue;
 91                 }
 92             }
 93 
 94             graph.edges[0, 1] = graph.edges[1, 0] = 80;
 95             graph.edges[0, 3] = graph.edges[3, 0] = 100;
 96             graph.edges[0, 5] = graph.edges[5, 0] = 20;
 97             graph.edges[1, 2] = graph.edges[2, 1] = 90;
 98             graph.edges[2, 5] = graph.edges[5, 2] = 70;
 99             graph.edges[4, 5] = graph.edges[5, 4] = 40;
100             graph.edges[3, 4] = graph.edges[4, 3] = 60;
101             graph.edges[2, 3] = graph.edges[3, 2] = 10;
102 
103             //優先隊列,存放樹中的邊
104             queue = new PriorityQueue<Edge>();
105 
106             //并查集
107             set = new DisjointSet<int>(graph.vertexs);
108 
109             //將對角線讀入到優先隊列
110             for (int i = 0; i < graph.vertexsNum; i++)
111             {
112                 for (int j = i; j < graph.vertexsNum; j++)
113                 {
114                     //說明該邊有權重
115                     if (graph.edges[i, j] != int.MaxValue)
116                     {
117                         queue.Eequeue(new Edge()
118                         {
119                             startEdge = i,
120                             endEdge = j,
121                             weight = graph.edges[i, j]
122                         }, graph.edges[i, j]);
123                     }
124                 }
125             }
126         }
127         #endregion
128 
129         #region 邊的信息
130         /// <summary>
131         /// 邊的信息
132         /// </summary>
133         public class Edge
134         {
135             //開始邊
136             public int startEdge;
137 
138             //結束邊
139             public int endEdge;
140 
141             //權重
142             public int weight;
143         }
144         #endregion
145 
146         #region Kruskal算法
147         /// <summary>
148         /// Kruskal算法
149         /// </summary>
150         public List<Edge> Kruskal()
151         {
152             //最后收集到的最小生成樹的邊
153             List<Edge> list = new List<Edge>();
154 
155             //循環隊列
156             while (queue.Count() > 0)
157             {
158                 var edge = queue.Dequeue();
159 
160                 //如果該兩點是同一個集合,則剔除該集合
161                 if (set.IsSameSet(edge.t.startEdge, edge.t.endEdge))
162                     continue;
163 
164                 list.Add(edge.t);
165 
166                 //然后將startEdge 和 endEdge Union起來,表示一個集合
167                 set.Union(edge.t.startEdge, edge.t.endEdge);
168 
169                 //如果n個節點有n-1邊的時候,此時生成樹已經構建完畢,提前退出
170                 if (list.Count == graph.vertexsNum - 1)
171                     break;
172             }
173 
174             return list;
175         }
176         #endregion
177     }
178     #endregion
179 }


推薦文章

發表評論:

◎歡迎參與討論,請在這里發表您的看法、交流您的觀點。

標簽列表
網站分類
最新留言

Powered By Z-BlogPHP and Terry

Copyright @ laigucomputer.com 來古計算機 工信部備案號:粵ICP備18009132號