00001 // 00002 // Copyright (c) 2006-2007, Benjamin Kaufmann 00003 // 00004 // This file is part of Clasp. See http://www.cs.uni-potsdam.de/clasp/ 00005 // 00006 // Clasp is free software; you can redistribute it and/or modify 00007 // it under the terms of the GNU General Public License as published by 00008 // the Free Software Foundation; either version 2 of the License, or 00009 // (at your option) any later version. 00010 // 00011 // Clasp is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 // GNU General Public License for more details. 00015 // 00016 // You should have received a copy of the GNU General Public License 00017 // along with Clasp; if not, write to the Free Software 00018 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00019 // 00020 #ifndef BK_LIB_INDEXED_PRIORITY_QUEUE_H_INCLUDED 00021 #define BK_LIB_INDEXED_PRIORITY_QUEUE_H_INCLUDED 00022 00023 #ifdef _MSC_VER 00024 #pragma warning (disable : 4267) 00025 #pragma warning (disable : 4244) 00026 #pragma once 00027 #endif 00028 00029 #include <cstddef> 00030 #include "pod_vector.h" 00031 namespace bk_lib { namespace detail { 00032 00033 typedef std::size_t key_type; 00034 const key_type noKey = static_cast<key_type>(-1); 00035 inline key_type heap_root() { return 0; } 00036 inline key_type heap_left(std::size_t i) { return (i<<1)+1; } 00037 inline key_type heap_right(std::size_t i) { return (i+1)<<1; } 00038 inline key_type heap_parent(std::size_t i) { return (i-1)>>1; } 00039 00040 } 00041 00042 // Note: Uses a Max-Heap! 00043 template < 00044 class Cmp // sort-predicate - if Cmp(k1, k2) == true, n1 has higher priority than n2 00045 > 00046 class indexed_priority_queue { 00047 public: 00048 typedef detail::key_type key_type; 00049 typedef pod_vector<key_type> index_container_type; 00050 typedef std::size_t size_type; 00051 typedef Cmp compare_type; 00052 00053 explicit indexed_priority_queue( const compare_type& c = compare_type() ); 00054 indexed_priority_queue(const indexed_priority_queue& other); 00055 00056 indexed_priority_queue& operator=(const indexed_priority_queue& other) { 00057 indices_ = other.indices_; 00058 heap_ = other.heap_; 00059 compare_ = other.compare_; 00060 return *this; 00061 } 00062 00063 const compare_type& key_compare() const { 00064 return compare_; 00065 } 00066 00067 bool empty() const { 00068 return heap_.empty(); 00069 } 00070 void reserve(size_type n) { 00071 indices_.reserve(n); 00072 } 00073 00074 void push(key_type k) { 00075 assert( !is_in_queue(k) ); 00076 if ((key_type)indices_.size() <= k) { 00077 if (indices_.capacity() <= k) { indices_.reserve(((k+1)*3)>>1); } 00078 indices_.resize(k+1, detail::noKey); 00079 } 00080 indices_[k] = (key_type)heap_.size(); 00081 heap_.push_back(k); 00082 siftup(indices_[k]); 00083 } 00084 00085 void pop() { 00086 assert(!empty()); 00087 key_type x = heap_[0]; 00088 heap_[0] = heap_.back(); 00089 indices_[heap_[0]] = 0; 00090 indices_[x] = detail::noKey; 00091 heap_.pop_back(); 00092 if (heap_.size() > 1) {siftdown(0);} 00093 } 00094 00095 void clear() { 00096 heap_.clear(); 00097 indices_.clear(); 00098 } 00099 00100 template <class C> 00101 void swapMem(indexed_priority_queue<C>& o) { 00102 clear(); 00103 o.clear(); 00104 heap_.swap(o.heap_); 00105 indices_.swap(o.indices_); 00106 } 00107 size_type size( ) const { 00108 return heap_.size(); 00109 } 00110 00111 key_type top() const { 00112 assert(!empty()); 00113 return heap_[0]; 00114 } 00115 00116 void update(key_type k) { 00117 if (!is_in_queue(k)) { 00118 push(k); 00119 } 00120 else { 00121 siftup(indices_[k]); 00122 siftdown(indices_[k]); 00123 } 00124 } 00125 // call if priority of k has increased 00126 void increase(key_type k) { 00127 assert(is_in_queue(k)); 00128 siftup(indices_[k]); 00129 } 00130 // call if priority of k has decreased 00131 void decrease(key_type k) { 00132 assert(is_in_queue(k)); 00133 siftdown(indices_[k]); 00134 } 00135 00136 bool is_in_queue(key_type k) const { 00137 assert(valid_key(k)); 00138 return k < (key_type)indices_.size() && indices_[k] != detail::noKey; 00139 } 00140 00141 void remove(key_type k) { 00142 if (is_in_queue(k)) { 00143 key_type kInHeap = indices_[k]; 00144 heap_[kInHeap] = heap_.back(); 00145 indices_[heap_.back()] = kInHeap; 00146 heap_.pop_back(); 00147 indices_[k] = detail::noKey; 00148 if (heap_.size() > 1 && kInHeap != (key_type)heap_.size()) { 00149 siftup(kInHeap); 00150 siftdown(kInHeap); 00151 } 00152 } 00153 } 00154 private: 00155 template <class X> 00156 friend class indexed_priority_queue; 00157 bool valid_key(key_type k) const { 00158 return k != detail::noKey; 00159 } 00160 index_container_type indices_; 00161 index_container_type heap_; 00162 compare_type compare_; 00163 void siftup(key_type n) { 00164 using namespace detail; 00165 key_type x = heap_[n]; 00166 key_type p = heap_parent(n); 00167 while (n != 0 && compare_(x, heap_[p])){ 00168 heap_[n] = heap_[p]; 00169 indices_[heap_[n]] = n; 00170 n = p; 00171 p = heap_parent(n); 00172 } 00173 heap_[n] = x; 00174 indices_[x] = n; 00175 } 00176 00177 void siftdown(key_type n) { 00178 using namespace detail; 00179 key_type x = heap_[n]; 00180 while (heap_left(n) < (key_type)heap_.size()){ 00181 key_type child = smaller_child(n); 00182 if (!compare_(heap_[child], x)) { 00183 break; 00184 } 00185 heap_[n] = heap_[child]; 00186 indices_[heap_[n]] = n; 00187 n = child; 00188 } 00189 heap_[n] = x; 00190 indices_[x] = n; 00191 } 00192 00193 key_type smaller_child(size_type n) const { 00194 using namespace detail; 00195 return heap_right(n) < (key_type)heap_.size() && compare_(heap_[heap_right(n)], heap_[heap_left(n)]) 00196 ? heap_right(n) 00197 : heap_left(n); 00198 } 00199 }; 00200 00201 template <class C> 00202 indexed_priority_queue<C>::indexed_priority_queue( const compare_type& c ) 00203 : indices_() 00204 , heap_() 00205 , compare_(c) { 00206 } 00207 00208 template <class C> 00209 indexed_priority_queue<C>::indexed_priority_queue(const indexed_priority_queue& other) 00210 : indices_(other.indices_) 00211 , heap_(other.heap_) 00212 , compare_(other.compare_) { 00213 } 00214 00215 } 00216 #endif