DS_Heap.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. /// \file DS_Heap.h
  11. /// \internal
  12. /// \brief Heap (Also serves as a priority queue)
  13. ///
  14. #ifndef __RAKNET_HEAP_H
  15. #define __RAKNET_HEAP_H
  16. #include "RakMemoryOverride.h"
  17. #include "DS_List.h"
  18. #include "Export.h"
  19. #include "RakAssert.h"
  20. #ifdef _MSC_VER
  21. #pragma warning( push )
  22. #endif
  23. /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
  24. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
  25. namespace DataStructures
  26. {
  27. template <class weight_type, class data_type, bool isMaxHeap>
  28. class RAK_DLL_EXPORT Heap
  29. {
  30. public:
  31. struct HeapNode
  32. {
  33. HeapNode() {}
  34. HeapNode(const weight_type &w, const data_type &d) : weight(w), data(d) {}
  35. weight_type weight; // I'm assuming key is a native numerical type - float or int
  36. data_type data;
  37. };
  38. Heap();
  39. ~Heap();
  40. void Push(const weight_type &weight, const data_type &data, const char *file, unsigned int line);
  41. /// Call before calling PushSeries, for a new series of items
  42. void StartSeries(void) {optimizeNextSeriesPush=false;}
  43. /// If you are going to push a list of items, where the weights of the items on the list are in order and follow the heap order, PushSeries is faster than Push()
  44. void PushSeries(const weight_type &weight, const data_type &data, const char *file, unsigned int line);
  45. data_type Pop(const unsigned startingIndex);
  46. data_type Peek(const unsigned startingIndex=0) const;
  47. weight_type PeekWeight(const unsigned startingIndex=0) const;
  48. void Clear(bool doNotDeallocateSmallBlocks, const char *file, unsigned int line);
  49. data_type& operator[] ( const unsigned int position ) const;
  50. unsigned Size(void) const;
  51. protected:
  52. unsigned LeftChild(const unsigned i) const;
  53. unsigned RightChild(const unsigned i) const;
  54. unsigned Parent(const unsigned i) const;
  55. void Swap(const unsigned i, const unsigned j);
  56. DataStructures::List<HeapNode> heap;
  57. bool optimizeNextSeriesPush;
  58. };
  59. template <class weight_type, class data_type, bool isMaxHeap>
  60. Heap<weight_type, data_type, isMaxHeap>::Heap()
  61. {
  62. optimizeNextSeriesPush=false;
  63. }
  64. template <class weight_type, class data_type, bool isMaxHeap>
  65. Heap<weight_type, data_type, isMaxHeap>::~Heap()
  66. {
  67. //Clear(true, _FILE_AND_LINE_);
  68. }
  69. template <class weight_type, class data_type, bool isMaxHeap>
  70. void Heap<weight_type, data_type, isMaxHeap>::PushSeries(const weight_type &weight, const data_type &data, const char *file, unsigned int line)
  71. {
  72. if (optimizeNextSeriesPush==false)
  73. {
  74. // If the weight of what we are inserting is greater than / less than in order of the heap of every sibling and sibling of parent, then can optimize next push
  75. unsigned currentIndex = heap.Size();
  76. unsigned parentIndex;
  77. if (currentIndex>0)
  78. {
  79. for (parentIndex = Parent(currentIndex); parentIndex < currentIndex; parentIndex++)
  80. {
  81. #ifdef _MSC_VER
  82. #pragma warning(disable:4127) // conditional expression is constant
  83. #endif
  84. if (isMaxHeap)
  85. {
  86. // Every child is less than its parent
  87. if (weight>heap[parentIndex].weight)
  88. {
  89. // Can't optimize
  90. Push(weight,data,file,line);
  91. return;
  92. }
  93. }
  94. else
  95. {
  96. // Every child is greater than than its parent
  97. if (weight<heap[parentIndex].weight)
  98. {
  99. // Can't optimize
  100. Push(weight,data,file,line);
  101. return;
  102. }
  103. }
  104. }
  105. }
  106. // Parent's subsequent siblings and this row's siblings all are less than / greater than inserted element. Can insert all further elements straight to the end
  107. heap.Insert(HeapNode(weight, data), file, line);
  108. optimizeNextSeriesPush=true;
  109. }
  110. else
  111. {
  112. heap.Insert(HeapNode(weight, data), file, line);
  113. }
  114. }
  115. template <class weight_type, class data_type, bool isMaxHeap>
  116. void Heap<weight_type, data_type, isMaxHeap>::Push(const weight_type &weight, const data_type &data, const char *file, unsigned int line)
  117. {
  118. unsigned currentIndex = heap.Size();
  119. unsigned parentIndex;
  120. heap.Insert(HeapNode(weight, data), file, line);
  121. while (currentIndex!=0)
  122. {
  123. parentIndex = Parent(currentIndex);
  124. #ifdef _MSC_VER
  125. #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
  126. #endif
  127. if (isMaxHeap)
  128. {
  129. if (heap[parentIndex].weight < weight)
  130. {
  131. Swap(currentIndex, parentIndex);
  132. currentIndex=parentIndex;
  133. }
  134. else
  135. break;
  136. }
  137. else
  138. {
  139. if (heap[parentIndex].weight > weight)
  140. {
  141. Swap(currentIndex, parentIndex);
  142. currentIndex=parentIndex;
  143. }
  144. else
  145. break;
  146. }
  147. }
  148. }
  149. template <class weight_type, class data_type, bool isMaxHeap>
  150. data_type Heap<weight_type, data_type, isMaxHeap>::Pop(const unsigned startingIndex)
  151. {
  152. // While we have children, swap out with the larger of the two children.
  153. // This line will assert on an empty heap
  154. data_type returnValue=heap[startingIndex].data;
  155. // Move the last element to the head, and re-heapify
  156. heap[startingIndex]=heap[heap.Size()-1];
  157. unsigned currentIndex,leftChild,rightChild;
  158. weight_type currentWeight;
  159. currentIndex=startingIndex;
  160. currentWeight=heap[startingIndex].weight;
  161. heap.RemoveFromEnd();
  162. #ifdef _MSC_VER
  163. #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
  164. #endif
  165. while (1)
  166. {
  167. leftChild=LeftChild(currentIndex);
  168. rightChild=RightChild(currentIndex);
  169. if (leftChild >= heap.Size())
  170. {
  171. // Done
  172. return returnValue;
  173. }
  174. if (rightChild >= heap.Size())
  175. {
  176. // Only left node.
  177. if ((isMaxHeap==true && currentWeight < heap[leftChild].weight) ||
  178. (isMaxHeap==false && currentWeight > heap[leftChild].weight))
  179. Swap(leftChild, currentIndex);
  180. return returnValue;
  181. }
  182. else
  183. {
  184. // Swap with the bigger/smaller of the two children and continue
  185. if (isMaxHeap)
  186. {
  187. if (heap[leftChild].weight <= currentWeight && heap[rightChild].weight <= currentWeight)
  188. return returnValue;
  189. if (heap[leftChild].weight > heap[rightChild].weight)
  190. {
  191. Swap(leftChild, currentIndex);
  192. currentIndex=leftChild;
  193. }
  194. else
  195. {
  196. Swap(rightChild, currentIndex);
  197. currentIndex=rightChild;
  198. }
  199. }
  200. else
  201. {
  202. if (heap[leftChild].weight >= currentWeight && heap[rightChild].weight >= currentWeight)
  203. return returnValue;
  204. if (heap[leftChild].weight < heap[rightChild].weight)
  205. {
  206. Swap(leftChild, currentIndex);
  207. currentIndex=leftChild;
  208. }
  209. else
  210. {
  211. Swap(rightChild, currentIndex);
  212. currentIndex=rightChild;
  213. }
  214. }
  215. }
  216. }
  217. }
  218. template <class weight_type, class data_type, bool isMaxHeap>
  219. inline data_type Heap<weight_type, data_type, isMaxHeap>::Peek(const unsigned startingIndex) const
  220. {
  221. return heap[startingIndex].data;
  222. }
  223. template <class weight_type, class data_type, bool isMaxHeap>
  224. inline weight_type Heap<weight_type, data_type, isMaxHeap>::PeekWeight(const unsigned startingIndex) const
  225. {
  226. return heap[startingIndex].weight;
  227. }
  228. template <class weight_type, class data_type, bool isMaxHeap>
  229. void Heap<weight_type, data_type, isMaxHeap>::Clear(bool doNotDeallocateSmallBlocks, const char *file, unsigned int line)
  230. {
  231. heap.Clear(doNotDeallocateSmallBlocks, file, line);
  232. }
  233. template <class weight_type, class data_type, bool isMaxHeap>
  234. inline data_type& Heap<weight_type, data_type, isMaxHeap>::operator[] ( const unsigned int position ) const
  235. {
  236. return heap[position].data;
  237. }
  238. template <class weight_type, class data_type, bool isMaxHeap>
  239. unsigned Heap<weight_type, data_type, isMaxHeap>::Size(void) const
  240. {
  241. return heap.Size();
  242. }
  243. template <class weight_type, class data_type, bool isMaxHeap>
  244. inline unsigned Heap<weight_type, data_type, isMaxHeap>::LeftChild(const unsigned i) const
  245. {
  246. return i*2+1;
  247. }
  248. template <class weight_type, class data_type, bool isMaxHeap>
  249. inline unsigned Heap<weight_type, data_type, isMaxHeap>::RightChild(const unsigned i) const
  250. {
  251. return i*2+2;
  252. }
  253. template <class weight_type, class data_type, bool isMaxHeap>
  254. inline unsigned Heap<weight_type, data_type, isMaxHeap>::Parent(const unsigned i) const
  255. {
  256. #ifdef _DEBUG
  257. RakAssert(i!=0);
  258. #endif
  259. return (i-1)/2;
  260. }
  261. template <class weight_type, class data_type, bool isMaxHeap>
  262. void Heap<weight_type, data_type, isMaxHeap>::Swap(const unsigned i, const unsigned j)
  263. {
  264. HeapNode temp;
  265. temp=heap[i];
  266. heap[i]=heap[j];
  267. heap[j]=temp;
  268. }
  269. }
  270. #ifdef _MSC_VER
  271. #pragma warning( pop )
  272. #endif
  273. #endif
粤ICP备19079148号