/// \file /// \brief \b [Internal] Heap (Also serves as a priority queue) /// /// This file is part of RakNet Copyright 2003 Kevin Jenkins. /// /// Usage of RakNet is subject to the appropriate license agreement. /// Creative Commons Licensees are subject to the /// license found at /// http://creativecommons.org/licenses/by-nc/2.5/ /// Single application licensees are subject to the license found at /// http://www.jenkinssoftware.com/SingleApplicationLicense.html /// Custom license users are subject to the terms therein. /// GPL license users are subject to the GNU General Public /// License as published by the Free /// Software Foundation; either version 2 of the License, or (at your /// option) any later version. #ifndef __RAKNET_HEAP_H #define __RAKNET_HEAP_H #include "RakMemoryOverride.h" #include "DS_List.h" #include "Export.h" #include #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 RAK_DLL_EXPORT Heap : public RakNet::RakMemoryOverride { 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); data_type Pop(const unsigned startingIndex); data_type Peek(const unsigned startingIndex=0) const; weight_type PeekWeight(const unsigned startingIndex=0) const; void Clear(void); 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 heap; }; template Heap::Heap() { } template Heap::~Heap() { Clear(); } template void Heap::Push(const weight_type &weight, const data_type &data) { unsigned currentIndex = heap.Size(); unsigned parentIndex; heap.Insert(HeapNode(weight, data)); 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 data_type Heap::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[0].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 data_type Heap::Peek(const unsigned startingIndex) const { return heap[startingIndex].data; } template weight_type Heap::PeekWeight(const unsigned startingIndex) const { return heap[startingIndex].weight; } template void Heap::Clear(void) { heap.Clear(); } template data_type& Heap::operator[] ( const unsigned int position ) const { return heap[position].data; } template unsigned Heap::Size(void) const { return heap.Size(); } template unsigned Heap::LeftChild(const unsigned i) const { return i*2+1; } template unsigned Heap::RightChild(const unsigned i) const { return i*2+2; } template unsigned Heap::Parent(const unsigned i) const { #ifdef _DEBUG assert(i!=0); #endif return (i-1)/2; } template void Heap::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