您的位置:首页 > 其它

经典算法题每日演练——第十六题 Kruskal算法

2012-12-17 00:28 393 查看
这篇我们看看第二种生成树的Kruskal算法,这个算法的魅力在于我们可以打一下算法和数据结构的组合拳,很有意思的。

一:思想

若存在M={0,1,2,3,4,5}这样6个节点,我们知道Prim算法构建生成树是从”顶点”这个角度来思考的,然后采用“贪心思想”

来一步步扩大化,最后形成整体最优解,而Kruskal算法有点意思,它是站在”边“这个角度在思考的,首先我有两个集合。

1. 顶点集合(vertexs):

比如M集合中的每个元素都可以认为是一个独根树(是不是想到了并查集?)。

2.边集合(edges):

对图中的每条边按照权值大小进行排序。(是不是想到了优先队列?)

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

首先:我们从edges中选出权值最小的一条边来作为生成树的一条边,然后将该边的两个顶点合并为一个新的树。

然后:我们继续从edges中选出次小的边作为生成树的第二条边,但是前提就是边的两个顶点一定是属于两个集合中,如果不是

则剔除该边继续选下一条次小边。

最后:经过反复操作,当我们发现n个顶点的图中生成树已经有n-1边的时候,此时生成树构建完毕。

View Code

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
9 namespace ConsoleApplication2
10 {
11     public class PriorityQueue<T> where T : class
12     {
13         /// <summary>
14         /// 定义一个数组来存放节点
15         /// </summary>
16         private List<HeapNode> nodeList = new List<HeapNode>();
17
18         #region 堆节点定义
19         /// <summary>
20         /// 堆节点定义
21         /// </summary>
22         public class HeapNode
23         {
24             /// <summary>
25             /// 实体数据
26             /// </summary>
27             public T t { get; set; }
28
29             /// <summary>
30             /// 优先级别 1-10个级别 (优先级别递增)
31             /// </summary>
32             public int level { get; set; }
33
34             public HeapNode(T t, int level)
35             {
36                 this.t = t;
37                 this.level = level;
38             }
39
40             public HeapNode() { }
41         }
42         #endregion
43
44         #region  添加操作
45         /// <summary>
46         /// 添加操作
47         /// </summary>
48         public void Eequeue(T t, int level = 1)
49         {
50             //将当前节点追加到堆尾
51             nodeList.Add(new HeapNode(t, level));
52
53             //如果只有一个节点,则不需要进行筛操作
54             if (nodeList.Count == 1)
55                 return;
56
57             //获取最后一个非叶子节点
58             int parent = nodeList.Count / 2 - 1;
59
60             //堆调整
61             UpHeapAdjust(nodeList, parent);
62         }
63         #endregion
64
65         #region 对堆进行上滤操作,使得满足堆性质
66         /// <summary>
67         /// 对堆进行上滤操作,使得满足堆性质
68         /// </summary>
69         /// <param name="nodeList"></param>
70         /// <param name="index">非叶子节点的之后指针(这里要注意:我们
71         /// 的筛操作时针对非叶节点的)
72         /// </param>
73         public void UpHeapAdjust(List<HeapNode> nodeList, int parent)
74         {
75             while (parent >= 0)
76             {
77                 //当前index节点的左孩子
78                 var left = 2 * parent + 1;
79
80                 //当前index节点的右孩子
81                 var right = left + 1;
82
83                 //parent子节点中最大的孩子节点,方便于parent进行比较
84                 //默认为left节点
85                 var min = left;
86
87                 //判断当前节点是否有右孩子
88                 if (right < nodeList.Count)
89                 {
90                     //判断parent要比较的最大子节点
91                     min = nodeList[left].level < nodeList[right].level ? left : right;
92                 }
93
94                 //如果parent节点大于它的某个子节点的话,此时筛操作
95                 if (nodeList[parent].level > nodeList[min].level)
96                 {
97                     //子节点和父节点进行交换操作
98                     var temp = nodeList[parent];
99                     nodeList[parent] = nodeList[min];
100                     nodeList[min] = temp;
101
102                     //继续进行更上一层的过滤
103                     parent = (int)Math.Ceiling(parent / 2d) - 1;
104                 }
105                 else
106                 {
107                     break;
108                 }
109             }
110         }
111         #endregion
112
113         #region 优先队列的出队操作
114         /// <summary>
115         /// 优先队列的出队操作
116         /// </summary>
117         /// <returns></returns>
118         public HeapNode Dequeue()
119         {
120             if (nodeList.Count == 0)
121                 return null;
122
123             //出队列操作,弹出数据头元素
124             var pop = nodeList[0];
125
126             //用尾元素填充头元素
127             nodeList[0] = nodeList[nodeList.Count - 1];
128
129             //删除尾节点
130             nodeList.RemoveAt(nodeList.Count - 1);
131
132             //然后从根节点下滤堆
133             DownHeapAdjust(nodeList, 0);
134
135             return pop;
136         }
137         #endregion
138
139         #region  对堆进行下滤操作,使得满足堆性质
140         /// <summary>
141         /// 对堆进行下滤操作,使得满足堆性质
142         /// </summary>
143         /// <param name="nodeList"></param>
144         /// <param name="index">非叶子节点的之后指针(这里要注意:我们
145         /// 的筛操作时针对非叶节点的)
146         /// </param>
147         public void DownHeapAdjust(List<HeapNode> nodeList, int parent)
148         {
149             while (2 * parent + 1 < nodeList.Count)
150             {
151                 //当前index节点的左孩子
152                 var left = 2 * parent + 1;
153
154                 //当前index节点的右孩子
155                 var right = left + 1;
156
157                 //parent子节点中最大的孩子节点,方便于parent进行比较
158                 //默认为left节点
159                 var min = left;
160
161                 //判断当前节点是否有右孩子
162                 if (right < nodeList.Count)
163                 {
164                     //判断parent要比较的最大子节点
165                     min = nodeList[left].level < nodeList[right].level ? left : right;
166                 }
167
168                 //如果parent节点小于它的某个子节点的话,此时筛操作
169                 if (nodeList[parent].level > nodeList[min].level)
170                 {
171                     //子节点和父节点进行交换操作
172                     var temp = nodeList[parent];
173                     nodeList[parent] = nodeList[min];
174                     nodeList[min] = temp;
175
176                     //继续进行更下一层的过滤
177                     parent = min;
178                 }
179                 else
180                 {
181                     break;
182                 }
183             }
184         }
185         #endregion
186
187         #region 获取元素并下降到指定的level级别
188         /// <summary>
189         /// 获取元素并下降到指定的level级别
190         /// </summary>
191         /// <returns></returns>
192         public HeapNode GetAndDownPriority(int level)
193         {
194             if (nodeList.Count == 0)
195                 return null;
196
197             //获取头元素
198             var pop = nodeList[0];
199
200             //设置指定优先级(如果为 MinValue 则为 -- 操作)
201             nodeList[0].level = level == int.MinValue ? --nodeList[0].level : level;
202
203             //下滤堆
204             DownHeapAdjust(nodeList, 0);
205
206             return nodeList[0];
207         }
208         #endregion
209
210         #region 获取元素并下降优先级
211         /// <summary>
212         /// 获取元素并下降优先级
213         /// </summary>
214         /// <returns></returns>
215         public HeapNode GetAndDownPriority()
216         {
217             //下降一个优先级
218             return GetAndDownPriority(int.MinValue);
219         }
220         #endregion
221
222         #region 返回当前优先队列中的元素个数
223         /// <summary>
224         /// 返回当前优先队列中的元素个数
225         /// </summary>
226         /// <returns></returns>
227         public int Count()
228         {
229             return nodeList.Count;
230         }
231         #endregion
232     }
233 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: