| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- /*
- * Copyright (c) 2014, Oculus VR, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- */
- /// \file DS_Heap.h
- /// \internal
- /// \brief Heap (Also serves as a priority queue)
- ///
- #ifndef __RAKNET_HEAP_H
- #define __RAKNET_HEAP_H
- #include "RakMemoryOverride.h"
- #include "DS_List.h"
- #include "Export.h"
- #include "RakAssert.h"
- #ifdef _MSC_VER
- #pragma warning( push )
- #endif
- /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
- /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
- namespace DataStructures
- {
- template <class weight_type, class data_type, bool isMaxHeap>
- class RAK_DLL_EXPORT Heap
- {
- public:
- struct HeapNode
- {
- HeapNode() {}
- HeapNode(const weight_type &w, const data_type &d) : weight(w), data(d) {}
- weight_type weight; // I'm assuming key is a native numerical type - float or int
- data_type data;
- };
- Heap();
- ~Heap();
- void Push(const weight_type &weight, const data_type &data, const char *file, unsigned int line);
- /// Call before calling PushSeries, for a new series of items
- void StartSeries(void) {optimizeNextSeriesPush=false;}
- /// 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()
- void PushSeries(const weight_type &weight, const data_type &data, const char *file, unsigned int line);
- data_type Pop(const unsigned startingIndex);
- data_type Peek(const unsigned startingIndex=0) const;
- weight_type PeekWeight(const unsigned startingIndex=0) const;
- void Clear(bool doNotDeallocateSmallBlocks, const char *file, unsigned int line);
- data_type& operator[] ( const unsigned int position ) const;
- unsigned Size(void) const;
- protected:
- unsigned LeftChild(const unsigned i) const;
- unsigned RightChild(const unsigned i) const;
- unsigned Parent(const unsigned i) const;
- void Swap(const unsigned i, const unsigned j);
- DataStructures::List<HeapNode> heap;
- bool optimizeNextSeriesPush;
- };
- template <class weight_type, class data_type, bool isMaxHeap>
- Heap<weight_type, data_type, isMaxHeap>::Heap()
- {
- optimizeNextSeriesPush=false;
- }
- template <class weight_type, class data_type, bool isMaxHeap>
- Heap<weight_type, data_type, isMaxHeap>::~Heap()
- {
- //Clear(true, _FILE_AND_LINE_);
- }
- template <class weight_type, class data_type, bool isMaxHeap>
- void Heap<weight_type, data_type, isMaxHeap>::PushSeries(const weight_type &weight, const data_type &data, const char *file, unsigned int line)
- {
- if (optimizeNextSeriesPush==false)
- {
- // 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
- unsigned currentIndex = heap.Size();
- unsigned parentIndex;
- if (currentIndex>0)
- {
- for (parentIndex = Parent(currentIndex); parentIndex < currentIndex; parentIndex++)
- {
- #ifdef _MSC_VER
- #pragma warning(disable:4127) // conditional expression is constant
- #endif
- if (isMaxHeap)
- {
- // Every child is less than its parent
- if (weight>heap[parentIndex].weight)
- {
- // Can't optimize
- Push(weight,data,file,line);
- return;
- }
- }
- else
- {
- // Every child is greater than than its parent
- if (weight<heap[parentIndex].weight)
- {
- // Can't optimize
- Push(weight,data,file,line);
- return;
- }
- }
- }
- }
- // 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
- heap.Insert(HeapNode(weight, data), file, line);
- optimizeNextSeriesPush=true;
- }
- else
- {
- heap.Insert(HeapNode(weight, data), file, line);
- }
- }
- template <class weight_type, class data_type, bool isMaxHeap>
- void Heap<weight_type, data_type, isMaxHeap>::Push(const weight_type &weight, const data_type &data, const char *file, unsigned int line)
- {
- unsigned currentIndex = heap.Size();
- unsigned parentIndex;
- heap.Insert(HeapNode(weight, data), file, line);
- while (currentIndex!=0)
- {
- parentIndex = Parent(currentIndex);
- #ifdef _MSC_VER
- #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
- #endif
- if (isMaxHeap)
- {
- if (heap[parentIndex].weight < weight)
- {
- Swap(currentIndex, parentIndex);
- currentIndex=parentIndex;
- }
- else
- break;
- }
- else
- {
- if (heap[parentIndex].weight > weight)
- {
- Swap(currentIndex, parentIndex);
- currentIndex=parentIndex;
- }
- else
- break;
- }
- }
- }
- template <class weight_type, class data_type, bool isMaxHeap>
- data_type Heap<weight_type, data_type, isMaxHeap>::Pop(const unsigned startingIndex)
- {
- // While we have children, swap out with the larger of the two children.
- // This line will assert on an empty heap
- data_type returnValue=heap[startingIndex].data;
- // Move the last element to the head, and re-heapify
- heap[startingIndex]=heap[heap.Size()-1];
- unsigned currentIndex,leftChild,rightChild;
- weight_type currentWeight;
- currentIndex=startingIndex;
- currentWeight=heap[startingIndex].weight;
- heap.RemoveFromEnd();
- #ifdef _MSC_VER
- #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
- #endif
- while (1)
- {
- leftChild=LeftChild(currentIndex);
- rightChild=RightChild(currentIndex);
- if (leftChild >= heap.Size())
- {
- // Done
- return returnValue;
- }
- if (rightChild >= heap.Size())
- {
- // Only left node.
- if ((isMaxHeap==true && currentWeight < heap[leftChild].weight) ||
- (isMaxHeap==false && currentWeight > heap[leftChild].weight))
- Swap(leftChild, currentIndex);
- return returnValue;
- }
- else
- {
- // Swap with the bigger/smaller of the two children and continue
- if (isMaxHeap)
- {
- if (heap[leftChild].weight <= currentWeight && heap[rightChild].weight <= currentWeight)
- return returnValue;
- if (heap[leftChild].weight > heap[rightChild].weight)
- {
- Swap(leftChild, currentIndex);
- currentIndex=leftChild;
- }
- else
- {
- Swap(rightChild, currentIndex);
- currentIndex=rightChild;
- }
- }
- else
- {
- if (heap[leftChild].weight >= currentWeight && heap[rightChild].weight >= currentWeight)
- return returnValue;
- if (heap[leftChild].weight < heap[rightChild].weight)
- {
- Swap(leftChild, currentIndex);
- currentIndex=leftChild;
- }
- else
- {
- Swap(rightChild, currentIndex);
- currentIndex=rightChild;
- }
- }
- }
- }
- }
- template <class weight_type, class data_type, bool isMaxHeap>
- inline data_type Heap<weight_type, data_type, isMaxHeap>::Peek(const unsigned startingIndex) const
- {
- return heap[startingIndex].data;
- }
- template <class weight_type, class data_type, bool isMaxHeap>
- inline weight_type Heap<weight_type, data_type, isMaxHeap>::PeekWeight(const unsigned startingIndex) const
- {
- return heap[startingIndex].weight;
- }
- template <class weight_type, class data_type, bool isMaxHeap>
- void Heap<weight_type, data_type, isMaxHeap>::Clear(bool doNotDeallocateSmallBlocks, const char *file, unsigned int line)
- {
- heap.Clear(doNotDeallocateSmallBlocks, file, line);
- }
- template <class weight_type, class data_type, bool isMaxHeap>
- inline data_type& Heap<weight_type, data_type, isMaxHeap>::operator[] ( const unsigned int position ) const
- {
- return heap[position].data;
- }
- template <class weight_type, class data_type, bool isMaxHeap>
- unsigned Heap<weight_type, data_type, isMaxHeap>::Size(void) const
- {
- return heap.Size();
- }
- template <class weight_type, class data_type, bool isMaxHeap>
- inline unsigned Heap<weight_type, data_type, isMaxHeap>::LeftChild(const unsigned i) const
- {
- return i*2+1;
- }
- template <class weight_type, class data_type, bool isMaxHeap>
- inline unsigned Heap<weight_type, data_type, isMaxHeap>::RightChild(const unsigned i) const
- {
- return i*2+2;
- }
- template <class weight_type, class data_type, bool isMaxHeap>
- inline unsigned Heap<weight_type, data_type, isMaxHeap>::Parent(const unsigned i) const
- {
- #ifdef _DEBUG
- RakAssert(i!=0);
- #endif
- return (i-1)/2;
- }
- template <class weight_type, class data_type, bool isMaxHeap>
- void Heap<weight_type, data_type, isMaxHeap>::Swap(const unsigned i, const unsigned j)
- {
- HeapNode temp;
- temp=heap[i];
- heap[i]=heap[j];
- heap[j]=temp;
- }
- }
- #ifdef _MSC_VER
- #pragma warning( pop )
- #endif
- #endif
|