2 using System.Collections.Generic;
5 using System.Diagnostics;
10 /// Why .NET doesn't already provide such a basic data structure
11 /// as a priority queue is anybody's best guess. This is an interface
12 /// for a queue class which treats the items themselves as keys,
13 /// the relative priorities being determined by a comparison between
16 /// <typeparam name="T">The type of item to queue. This must be a
17 /// comparable class.</typeparam>
18 public interface IPriorityQueue<T> where T : IComparable<T>
21 /// Add a new item to the priority queue.
23 /// <param name="item">The item to add.</param>
27 /// Get the item with the highest priority, removing it
28 /// from the priority queue.
30 /// <returns>The highest priority item.</returns>
34 /// Get the item with the highest priority, but keep it in
35 /// the priority queue.
37 /// <returns>The highest priority item.</returns>
41 /// Notify the priority queue that the priority of a certain item
42 /// has improved. If the items is not in the queue, it is added.
43 /// Do not use this to demote items. The internal structures will
44 /// be reconfigured in order to ensure correct priority queueing.
46 /// <param name="item">The item that improved.</param>
50 /// Remove all the items from the priority queue.
55 /// Get the number of items in the priority queue.
62 /// A minimum binary heap implementing a priority queue.
64 /// <typeparam name="T">The type of items to load in the heap.</typeparam>
65 public class BinaryHeap<T> : IPriorityQueue<T> where T : IComparable<T>
67 #region Public Properties
70 /// Get the number of items in the binary heap.
72 public int Count { get { return mSize; } }
77 #region Public Methods
80 /// Construct a binary heap.
84 mList.Add(default(T));
88 /// Construct a binary heap with a predetermined capacity.
89 /// The heap is dynamically-sized, but it will be more
90 /// efficient if you set the capacity to the number of items
93 /// <param name="capacity">The capacity of the heap.</param>
94 public BinaryHeap(int capacity)
96 mList.Capacity = capacity;
97 mList.Add(default(T));
102 /// Add a new item to the heap.
104 /// <param name="item">The item to add.</param>
105 public void Add(T item)
114 /// Get the item with the lowest value, removing it from the heap.
116 /// <returns>The highest priority item.</returns>
119 Debug.Assert(mSize > 0);
123 mList[1] = mList[mSize];
125 mList.RemoveAt(mSize);
132 /// Get the item with the lowest value, but keep it in the heap.
134 /// <returns>The highest priority item.</returns>
137 Debug.Assert(mSize > 0);
144 /// Decrease the value of one of the items in the heap. If the
145 /// item is not already in the heap, it is added.
147 /// <param name="item">The item to change.</param>
148 public void Promote(T item)
150 for (int i = 1; i < mList.Count; i++)
152 if (item.Equals(mList[i]))
155 if (PercolateUp(i) == i) PercolateDown(i);
165 /// Remove all the items from the heap.
176 #region Private Methods
178 int PercolateUp(int index)
180 T temp = mList[index];
182 for (int parent; index > 1; index = parent)
185 if (temp.CompareTo(mList[parent]) < 0) mList[index] = mList[parent];
193 int PercolateDown(int index)
195 T temp = mList[index];
197 for (int child; index * 2 <= mSize; index = child)
200 if (child != mSize && mList[child].CompareTo(mList[child + 1]) > 0) child++;
201 if (temp.CompareTo(mList[child]) > 0) mList[index] = mList[child];
212 #region Private Variables
214 List<T> mList = new List<T>();
222 /// The binary heap might be too slow for shortest path algorithms,
223 /// so here is a fibonacci heap which should perform better.
225 /// <typeparam name="T">The type of items to load in the heap.</typeparam>
226 public class FibonacciHeap<T> : IPriorityQueue<T> where T : IComparable<T>
228 #region Public Properties
231 /// Get the number of items in the fibonacci heap.
233 public int Count { get { return mCount; } }
238 #region Public Methods
241 /// Construct an empty fibonacci heap.
243 public FibonacciHeap()
245 mList = new LinkedList<NodeInfo>();
246 mLookup = new Dictionary<T, LinkedListNode<NodeInfo>>();
251 /// Add a new item to the heap.
253 /// <param name="item">The item to add.</param>
254 public void Add(T item)
256 LinkedListNode<NodeInfo> node = mList.AddLast(new NodeInfo(item));
257 if (mMin == null || item.CompareTo(mMin.Value.Item) < 0) mMin = node;
259 mLookup[item] = node;
265 /// Get the item with the lowest value, removing it from the heap.
267 /// <returns>The highest priority item.</returns>
270 LinkedListNode<NodeInfo> temp = mMin;
274 LinkedListNode<NodeInfo> node = temp.Value.Children.First;
278 node = temp.Value.Children.First;
282 mLookup.Remove(temp.Value.Item);
284 return temp.Value.Item;
288 /// Get the item with the lowest value, but keep it in the heap.
290 /// <returns>The highest priority item.</returns>
293 return mMin.Value.Item;
298 /// Decrease the value of one of the items in the heap. If the
299 /// item is not already in the heap, it is added.
301 /// <param name="item">The item to change.</param>
302 public void Promote(T item)
304 LinkedListNode<NodeInfo> node;
305 if (mLookup.TryGetValue(item, out node))
307 LinkedListNode<NodeInfo> parent = node.Value.Parent;
310 if (node.Value.Item.CompareTo(parent.Value.Item) < 0)
313 CascadingCut(parent);
314 if (node.Value.Item.CompareTo(mMin.Value.Item) < 0) mMin = node;
317 else if (node.Value.Item.CompareTo(mMin.Value.Item) < 0) mMin = node;
327 /// Remove all the items from the heap.
340 #region Private Methods
342 // Builds up the binomial trees. More importantly, it sets the min
343 // pointeer and ensures that no root binomial tree has the same degree.
346 LinkedListNode<NodeInfo>[] degree = new LinkedListNode<NodeInfo>[64];
348 for (LinkedListNode<NodeInfo> node = mList.First; node != null;)
350 LinkedListNode<NodeInfo> match = degree[node.Value.Degree];
353 if (mMin == null || node.Value.Item.CompareTo(mMin.Value.Item) <= 0) mMin = node;
354 degree[node.Value.Degree] = node;
360 degree[node.Value.Degree] = null;
362 if (node.Value.Item.CompareTo(match.Value.Item) < 0)
369 mList.AddAfter(node, match);
377 // Removes child from whatever list it is in and makes it a child
378 // of parent. This is for building up the binomial trees.
379 void Link(LinkedListNode<NodeInfo> child, LinkedListNode<NodeInfo> parent)
381 child.List.Remove(child);
382 parent.Value.Children.AddLast(child);
383 child.Value.Parent = parent;
384 child.Value.IsMarked = false;
387 // Removes node from whatever list it is in and makes it a root binomial
389 void Cut(LinkedListNode<NodeInfo> node)
391 node.List.Remove(node);
393 node.Value.Parent = null;
394 node.Value.IsMarked = false;
397 // Cuts each node that is marked, following the ancestry until it finds
398 // an unmarked ancestor (in which case it marks it) or a root node.
399 void CascadingCut(LinkedListNode<NodeInfo> node)
401 while (node.Value.Parent != null)
403 if (node.Value.IsMarked)
406 node = node.Value.Parent;
410 node.Value.IsMarked = true;
419 #region Private Types
421 // This container class has the information we need to form
422 // a tree out of linked lists.
425 public LinkedListNode<NodeInfo> Parent;
426 public LinkedList<NodeInfo> Children = new LinkedList<NodeInfo>();
427 public bool IsMarked = false;
429 public int Degree { get { return Children.Count; } }
431 public T Item { get { return mItem; } }
433 public NodeInfo(T item)
444 #region Private Variables
446 LinkedList<NodeInfo> mList;
447 LinkedListNode<NodeInfo> mMin;
450 // To speed up promotions, we need a fast lookup for nodes.
451 Dictionary<T, LinkedListNode<NodeInfo>> mLookup;