|
Britbot
|
00001 #region Usings 00002 00003 using System; 00004 using System.Collections; 00005 using System.Collections.Generic; 00006 00007 #endregion 00008 00009 namespace Britbot.PriorityQueue 00010 { 00016 public sealed class HeapPriorityQueue<T> : IPriorityQueue<T> 00017 where T : PriorityQueueNode 00018 { 00019 private T[] _nodes; 00020 private long _numNodesEverEnqueued; 00021 00026 public HeapPriorityQueue(int maxNodes) 00027 { 00028 this.Count = 0; 00029 this._nodes = new T[maxNodes + 1]; 00030 this._numNodesEverEnqueued = 0; 00031 } 00032 00037 public void Set(HeapPriorityQueue<T> queue) 00038 { 00039 this.Count = queue.Count; 00040 //this._nodes = new T[queue._nodes.Length]; 00041 this._numNodesEverEnqueued = queue._numNodesEverEnqueued; 00042 //copy array 00043 for(int i = 0; i < queue._numNodesEverEnqueued;i++) 00044 { 00045 this._nodes[i] = queue._nodes[i]; 00046 } 00047 } 00051 public int Count { get; private set; } 00052 00058 public int MaxSize 00059 { 00060 get { return this._nodes.Length - 1; } 00061 } 00062 00066 #if NET_VERSION_4_5 00067 [MethodImpl(MethodImplOptions.AggressiveInlining)] 00068 #endif 00069 public void Clear() 00070 { 00071 Array.Clear(this._nodes, 1, this.Count); 00072 this.Count = 0; 00073 } 00074 00078 #if NET_VERSION_4_5 00079 [MethodImpl(MethodImplOptions.AggressiveInlining)] 00080 #endif 00081 public bool Contains(T node) 00082 { 00083 return (this._nodes[node.QueueIndex] == node); 00084 } 00085 00089 #if NET_VERSION_4_5 00090 [MethodImpl(MethodImplOptions.AggressiveInlining)] 00091 #endif 00092 public void Enqueue(T node, double priority) 00093 { 00094 node.Priority = priority; 00095 this.Count++; 00096 this._nodes[this.Count] = node; 00097 node.QueueIndex = this.Count; 00098 node.InsertionIndex = this._numNodesEverEnqueued++; 00099 this.CascadeUp(this._nodes[this.Count]); 00100 } 00101 00102 #if NET_VERSION_4_5 00103 [MethodImpl(MethodImplOptions.AggressiveInlining)] 00104 #endif 00105 00106 private void Swap(T node1, T node2) 00107 { 00108 //Swap the nodes 00109 this._nodes[node1.QueueIndex] = node2; 00110 this._nodes[node2.QueueIndex] = node1; 00111 00112 //Swap their indicies 00113 int temp = node1.QueueIndex; 00114 node1.QueueIndex = node2.QueueIndex; 00115 node2.QueueIndex = temp; 00116 } 00117 00118 //Performance appears to be slightly better when this is NOT inlined o_O 00119 private void CascadeUp(T node) 00120 { 00121 //aka Heapify-up 00122 int parent = node.QueueIndex / 2; 00123 while (parent >= 1) 00124 { 00125 T parentNode = this._nodes[parent]; 00126 if (this.HasHigherPriority(parentNode, node)) 00127 break; 00128 00129 //Node has lower priority value, so move it up the heap 00130 this.Swap(node, parentNode); 00131 //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown() 00132 00133 parent = node.QueueIndex / 2; 00134 } 00135 } 00136 00137 #if NET_VERSION_4_5 00138 [MethodImpl(MethodImplOptions.AggressiveInlining)] 00139 #endif 00140 00141 private void CascadeDown(T node) 00142 { 00143 //aka Heapify-down 00144 T newParent; 00145 int finalQueueIndex = node.QueueIndex; 00146 while (true) 00147 { 00148 newParent = node; 00149 int childLeftIndex = 2 * finalQueueIndex; 00150 00151 //Check if the left-child is higher-priority than the current node 00152 if (childLeftIndex > this.Count) 00153 { 00154 //This could be placed outside the loop, but then we'd have to check newParent != node twice 00155 node.QueueIndex = finalQueueIndex; 00156 this._nodes[finalQueueIndex] = node; 00157 break; 00158 } 00159 00160 T childLeft = this._nodes[childLeftIndex]; 00161 if (this.HasHigherPriority(childLeft, newParent)) 00162 { 00163 newParent = childLeft; 00164 } 00165 00166 //Check if the right-child is higher-priority than either the current node or the left child 00167 int childRightIndex = childLeftIndex + 1; 00168 if (childRightIndex <= this.Count) 00169 { 00170 T childRight = this._nodes[childRightIndex]; 00171 if (this.HasHigherPriority(childRight, newParent)) 00172 { 00173 newParent = childRight; 00174 } 00175 } 00176 00177 //If either of the children has higher (smaller) priority, swap and continue cascading 00178 if (newParent != node) 00179 { 00180 //Move new parent to its new index. node will be moved once, at the end 00181 //Doing it this way is one less assignment operation than calling Swap() 00182 this._nodes[finalQueueIndex] = newParent; 00183 00184 int temp = newParent.QueueIndex; 00185 newParent.QueueIndex = finalQueueIndex; 00186 finalQueueIndex = temp; 00187 } 00188 else 00189 { 00190 //See note above 00191 node.QueueIndex = finalQueueIndex; 00192 this._nodes[finalQueueIndex] = node; 00193 break; 00194 } 00195 } 00196 } 00197 00202 #if NET_VERSION_4_5 00203 [MethodImpl(MethodImplOptions.AggressiveInlining)] 00204 #endif 00205 private bool HasHigherPriority(T higher, T lower) 00206 { 00207 return (higher.Priority < lower.Priority || 00208 (Math.Abs(higher.Priority - lower.Priority) < 0.01 && higher.InsertionIndex < lower.InsertionIndex)); 00209 } 00210 00215 public T Dequeue() 00216 { 00217 T returnMe = this._nodes[1]; 00218 this.Remove(returnMe); 00219 return returnMe; 00220 } 00221 00225 public T First 00226 { 00227 get { return this._nodes[1]; } 00228 } 00229 00235 #if NET_VERSION_4_5 00236 [MethodImpl(MethodImplOptions.AggressiveInlining)] 00237 #endif 00238 public void UpdatePriority(T node, double priority) 00239 { 00240 node.Priority = priority; 00241 this.OnNodeUpdated(node); 00242 } 00243 00244 private void OnNodeUpdated(T node) 00245 { 00246 //Bubble the updated node up or down as appropriate 00247 int parentIndex = node.QueueIndex / 2; 00248 T parentNode = this._nodes[parentIndex]; 00249 00250 if (parentIndex > 0 && this.HasHigherPriority(node, parentNode)) 00251 { 00252 this.CascadeUp(node); 00253 } 00254 else 00255 { 00256 //Note that CascadeDown will be called if parentNode == node (that is, node is the root) 00257 this.CascadeDown(node); 00258 } 00259 } 00260 00264 public void Remove(T node) 00265 { 00266 if (!this.Contains(node)) 00267 { 00268 return; 00269 } 00270 00271 if (this.Count <= 1) 00272 { 00273 this._nodes[1] = null; 00274 this.Count = 0; 00275 return; 00276 } 00277 00278 //Make sure the node is the last node in the queue 00279 bool wasSwapped = false; 00280 T formerLastNode = this._nodes[this.Count]; 00281 if (node.QueueIndex != this.Count) 00282 { 00283 //Swap the node with the last node 00284 this.Swap(node, formerLastNode); 00285 wasSwapped = true; 00286 } 00287 00288 this.Count--; 00289 this._nodes[node.QueueIndex] = null; 00290 00291 if (wasSwapped) 00292 { 00293 //Now bubble formerLastNode (which is no longer the last node) up or down as appropriate 00294 this.OnNodeUpdated(formerLastNode); 00295 } 00296 } 00297 00298 public IEnumerator<T> GetEnumerator() 00299 { 00300 for (int i = 1; i <= this.Count; i++) 00301 yield return this._nodes[i]; 00302 } 00303 00304 IEnumerator IEnumerable.GetEnumerator() 00305 { 00306 return this.GetEnumerator(); 00307 } 00308 00313 public bool IsValidQueue() 00314 { 00315 for (int i = 1; i < this._nodes.Length; i++) 00316 { 00317 if (this._nodes[i] != null) 00318 { 00319 int childLeftIndex = 2 * i; 00320 if (childLeftIndex < this._nodes.Length && this._nodes[childLeftIndex] != null && 00321 this.HasHigherPriority(this._nodes[childLeftIndex], this._nodes[i])) 00322 return false; 00323 00324 int childRightIndex = childLeftIndex + 1; 00325 if (childRightIndex < this._nodes.Length && this._nodes[childRightIndex] != null && 00326 this.HasHigherPriority(this._nodes[childRightIndex], this._nodes[i])) 00327 return false; 00328 } 00329 } 00330 return true; 00331 } 00332 } 00333 }
1.7.6.1