Subversion Repositories Games.Chess Giants

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.     Texel - A UCI chess engine.
  3.     Copyright (C) 2013  Peter Ă–sterlund, peterosterlund2@gmail.com
  4.  
  5.     This program is free software: you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation, either version 3 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17. */
  18.  
  19. /*
  20.  * heap.hpp
  21.  *
  22.  *  Created on: Oct 3, 2013
  23.  *      Author: petero
  24.  */
  25.  
  26. #ifndef HEAP_HPP_
  27. #define HEAP_HPP_
  28.  
  29. #include <vector>
  30. #include <memory>
  31. #include <type_traits>
  32. #include <iostream>
  33.  
  34. template <typename T> class Heap;
  35.  
  36. /** A Heap that holds pointers to elements of type T.
  37.  * T must inherit from HeapObject.
  38.  * Destructing a T removes it from its heap.
  39.  */
  40. template <typename T>
  41. class Heap {
  42. public:
  43.     /** Base class for objects that can be inserted in a heap. */
  44.     class HeapObject {
  45.     public:
  46.         HeapObject();
  47.         ~HeapObject();
  48.         HeapObject(const HeapObject&) = delete;
  49.         HeapObject& operator=(const HeapObject&) = delete;
  50.  
  51.         /** Get priority of element in heap. */
  52.         int getPrio() const;
  53.  
  54.         /** Changes the priority. Does nothing if element not in a heap. */
  55.         void newPrio(int prio);
  56.     private:
  57.         friend class Heap;
  58.  
  59.         Heap<T>* owner;
  60.         int prio;
  61.         int heapIdx;
  62.     };
  63.  
  64.     /** Constructor. Creates an empty heap. */
  65.     Heap();
  66.  
  67.     /** Destructor. Removes all elements from heap. */
  68.     ~Heap();
  69.  
  70.     Heap(const Heap& other) = delete;
  71.     Heap& operator=(const Heap& other) = delete;
  72.  
  73.     /** Insert an element in the heap. */
  74.     void insert(const std::shared_ptr<T>& e, int prio);
  75.  
  76.     /** Remove an element from the heap. Does nothing if e not in heap. */
  77.     void remove(const std::shared_ptr<T>& e);
  78.     void remove(T* e);
  79.  
  80.     /** Change the priority of an element in the heap. */
  81.     void newPrio(const std::shared_ptr<T>& e, int prio);
  82.     void newPrio(T* e, int prio);
  83.  
  84.     /** Get the element with the highest priority. The element is not removed.
  85.      * Returns null if heap is empty. */
  86.     std::shared_ptr<T> front() const;
  87.  
  88.     /** Return true if heap is empty. */
  89.     bool empty() const;
  90.  
  91.     /** Return number of elements in the heap. */
  92.     int size() const;
  93.  
  94.     /** For debugging. */
  95.     void print(std::ostream& os) const;
  96.  
  97. private:
  98.     /** Swap two elements in the heap vector and update heapIdx. */
  99.     void swapElems(int idx1, int idx2);
  100.  
  101.     /** Calls upHeap() or downHeap() as needed to restore heap condition. */
  102.     void fixHeap(int idx);
  103.  
  104.     /** Moves an element up until the heap condition is satisfied.*/
  105.     void upHeap(int idx);
  106.  
  107.     /** Moves an element down until the heap condition is satisfied. */
  108.     void downHeap(int idx);
  109.  
  110.     /** Vector of heap elements. */
  111.     std::vector<std::shared_ptr<T>> heap;
  112. };
  113.  
  114. template <typename T> inline Heap<T>::Heap() {
  115.     static_assert(std::is_base_of<HeapObject,T>::value, "T must inherit HeapObject");
  116. }
  117.  
  118. template <typename T> inline Heap<T>::~Heap() {
  119.     for (int i = (int)heap.size() - 1; i >= 0; i--)
  120.         remove(heap[i]);
  121. }
  122.  
  123. template <typename T> inline void Heap<T>::insert(const std::shared_ptr<T>& e, int prio) {
  124.     assert(!e->owner);
  125.     e->owner = this;
  126.     e->prio = prio;
  127.     int idx = (int)heap.size();
  128.     e->heapIdx = idx;
  129.     heap.push_back(e);
  130.     upHeap(idx);
  131. }
  132.  
  133. template <typename T> inline void Heap<T>::remove(const std::shared_ptr<T>& e) {
  134.     remove(e.get());
  135. }
  136.  
  137. template <typename T> inline void Heap<T>::remove(T* e) {
  138.     if (!e->owner)
  139.         return;
  140.     int idx = e->heapIdx;
  141.     int last = (int)heap.size() - 1;
  142.     if (idx < last)
  143.         swapElems(e->heapIdx, last);
  144.     e->owner = nullptr;
  145.     e->heapIdx = -1;
  146.     heap.pop_back();
  147.     if (idx < last)
  148.         fixHeap(idx);
  149. }
  150.  
  151. template <typename T> inline void Heap<T>::newPrio(const std::shared_ptr<T>& e, int prio) {
  152.     newPrio(e.get(), prio);
  153. }
  154.  
  155. template <typename T> inline void Heap<T>::newPrio(T* e, int prio) {
  156.     e->prio = prio;
  157.     fixHeap(e->heapIdx);
  158. }
  159.  
  160. template <typename T> inline std::shared_ptr<T> Heap<T>::front() const {
  161.     if (heap.empty())
  162.         return nullptr;
  163.     return heap[0];
  164. }
  165.  
  166. template <typename T> bool Heap<T>::empty() const {
  167.     return heap.empty();
  168. }
  169.  
  170. template <typename T> int Heap<T>::size() const {
  171.     return (int)heap.size();
  172. }
  173.  
  174. template <typename T> inline void Heap<T>::swapElems(int idx1, int idx2) {
  175.     std::swap(heap[idx1]->heapIdx, heap[idx2]->heapIdx);
  176.     heap[idx1].swap(heap[idx2]);
  177. }
  178.  
  179. template <typename T> inline void Heap<T>::fixHeap(int idx) {
  180.     int parent = (idx - 1) / 2;
  181.     if ((idx > 0) && (heap[parent]->prio < heap[idx]->prio)) {
  182.         swapElems(idx, parent);
  183.         upHeap(parent);
  184.     } else {
  185.         downHeap(idx);
  186.     }
  187. }
  188.  
  189. template <typename T> inline void Heap<T>::upHeap(int idx) {
  190.     while (idx > 0) {
  191.         int parent = (idx - 1) / 2;
  192.         if (heap[parent]->prio >= heap[idx]->prio)
  193.             break;
  194.         swapElems(idx, parent);
  195.         idx = parent;
  196.     }
  197. }
  198.  
  199. template <typename T> inline void Heap<T>::downHeap(int idx) {
  200.     int hSize = (int)heap.size();
  201.     while (true) {
  202.         int child = idx * 2 + 1;
  203.         if (child >= hSize)
  204.             break;
  205.         if ((child + 1 < hSize) && (heap[child]->prio < heap[child+1]->prio))
  206.             child++;
  207.         if (heap[idx]->prio >= heap[child]->prio)
  208.             break;
  209.         swapElems(idx, child);
  210.         idx = child;
  211.     }
  212. }
  213.  
  214. template <typename T> inline Heap<T>::HeapObject::HeapObject()
  215.     : owner(nullptr), prio(0), heapIdx(-1) {
  216. }
  217.  
  218. template <typename T> inline Heap<T>::HeapObject::~HeapObject() {
  219.     if (owner)
  220.         owner->remove(static_cast<T*>(this));
  221. }
  222.  
  223. template <typename T> inline int Heap<T>::HeapObject::getPrio() const {
  224.     return prio;
  225. }
  226.  
  227. template <typename T> inline void Heap<T>::HeapObject::newPrio(int prio) {
  228.     if (owner)
  229.         owner->newPrio(static_cast<T*>(this), prio);
  230. }
  231.  
  232. template <typename T> inline void Heap<T>::print(std::ostream& os) const {
  233.     int hSize = heap.size();
  234.     for (int i = 0; i < hSize; i++)
  235.         os << std::setw(2) << i << ' ';
  236.     os << '\n';
  237.     for (int i = 0; i < hSize; i++)
  238.         os << std::setw(2) << heap[i]->prio << ' ';
  239.     os << '\n';
  240. }
  241.  
  242. #endif /* HEAP_HPP_ */
  243.