lemon/linear_heap.h
changeset 1724 b20777184ba8
child 1758 4bfe670710e0
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/lemon/linear_heap.h	Fri Oct 14 10:58:54 2005 +0000
     1.3 @@ -0,0 +1,486 @@
     1.4 +/* -*- C++ -*-
     1.5 + * lemon/linear_heap.h - Part of LEMON, a generic C++ optimization library
     1.6 + *
     1.7 + * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     1.8 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
     1.9 + *
    1.10 + * Permission to use, modify and distribute this software is granted
    1.11 + * provided that this copyright notice appears in all copies. For
    1.12 + * precise terms see the accompanying LICENSE file.
    1.13 + *
    1.14 + * This software is provided "AS IS" with no warranty of any kind,
    1.15 + * express or implied, and with no claim as to its suitability for any
    1.16 + * purpose.
    1.17 + *
    1.18 + */
    1.19 +
    1.20 +#ifndef LEMON_LINEAR_HEAP_H
    1.21 +#define LEMON_LINEAR_HEAP_H
    1.22 +
    1.23 +///\ingroup auxdat
    1.24 +///\file
    1.25 +///\brief Binary Heap implementation.
    1.26 +
    1.27 +#include <vector>
    1.28 +#include <utility>
    1.29 +#include <functional>
    1.30 +
    1.31 +namespace lemon {
    1.32 +
    1.33 +  /// \addtogroup auxdat
    1.34 +  /// @{
    1.35 +
    1.36 +  /// \brief A Linear Heap implementation.
    1.37 +  ///
    1.38 +  /// This class implements the \e linear \e heap data structure. A \e heap
    1.39 +  /// is a data structure for storing items with specified values called \e
    1.40 +  /// priorities in such a way that finding the item with minimum priority is
    1.41 +  /// efficient. The linear heap is very simple implementation, it can store
    1.42 +  /// only integer priorities and it stores for each priority in the [0..C]
    1.43 +  /// range a list of items. So it should be used only when the priorities
    1.44 +  /// are small. It is not intended to use as dijkstra heap.
    1.45 +  ///
    1.46 +  /// \param _Item Type of the items to be stored.  
    1.47 +  /// \param _ItemIntMap A read and writable Item int map, used internally
    1.48 +  /// to handle the cross references.
    1.49 +  /// \param minimize If the given parameter is true then the heap gives back
    1.50 +  /// the lowest priority. 
    1.51 +  template <typename _Item, typename _ItemIntMap, bool minimize = true >
    1.52 +  class LinearHeap {
    1.53 +
    1.54 +  public:
    1.55 +    typedef _Item Item;
    1.56 +    typedef int Prio;
    1.57 +    typedef std::pair<Item, Prio> Pair;
    1.58 +    typedef _ItemIntMap ItemIntMap;
    1.59 +
    1.60 +    /// \brief Type to represent the items states.
    1.61 +    ///
    1.62 +    /// Each Item element have a state associated to it. It may be "in heap",
    1.63 +    /// "pre heap" or "post heap". The latter two are indifferent from the
    1.64 +    /// heap's point of view, but may be useful to the user.
    1.65 +    ///
    1.66 +    /// The ItemIntMap \e should be initialized in such way that it maps
    1.67 +    /// PRE_HEAP (-1) to any element to be put in the heap...
    1.68 +    enum state_enum {
    1.69 +      IN_HEAP = 0,
    1.70 +      PRE_HEAP = -1,
    1.71 +      POST_HEAP = -2
    1.72 +    };
    1.73 +
    1.74 +  public:
    1.75 +    /// \brief The constructor.
    1.76 +    ///
    1.77 +    /// The constructor.
    1.78 +    /// \param _index should be given to the constructor, since it is used
    1.79 +    /// internally to handle the cross references. The value of the map
    1.80 +    /// should be PRE_HEAP (-1) for each element.
    1.81 +    explicit LinearHeap(ItemIntMap &_index) : index(_index), minimal(0) {}
    1.82 +    
    1.83 +    /// The number of items stored in the heap.
    1.84 +    ///
    1.85 +    /// \brief Returns the number of items stored in the heap.
    1.86 +    int size() const { return data.size(); }
    1.87 +    
    1.88 +    /// \brief Checks if the heap stores no items.
    1.89 +    ///
    1.90 +    /// Returns \c true if and only if the heap stores no items.
    1.91 +    bool empty() const { return data.empty(); }
    1.92 +
    1.93 +    /// \brief Make empty this heap.
    1.94 +    /// 
    1.95 +    /// Make empty this heap.
    1.96 +    void clear() { 
    1.97 +      for (int i = 0; i < (int)data.size(); ++i) {
    1.98 +	index[data[i].item] = -2;
    1.99 +      }
   1.100 +      data.clear(); first.clear(); minimal = 0;
   1.101 +    }
   1.102 +
   1.103 +  private:
   1.104 +
   1.105 +    void relocate_last(int idx) {
   1.106 +      if (idx + 1 < (int)data.size()) {
   1.107 +	data[idx] = data.back();
   1.108 +	if (data[idx].prev != -1) {
   1.109 +	  data[data[idx].prev].next = idx;
   1.110 +	} else {
   1.111 +	  first[data[idx].value] = idx;
   1.112 +	}
   1.113 +	if (data[idx].next != -1) {
   1.114 +	  data[data[idx].next].prev = idx;
   1.115 +	}
   1.116 +	index[data[idx].item] = idx;
   1.117 +      }
   1.118 +      data.pop_back();
   1.119 +    }
   1.120 +
   1.121 +    void unlace(int idx) {
   1.122 +      if (data[idx].prev != -1) {
   1.123 +	data[data[idx].prev].next = data[idx].next;
   1.124 +      } else {
   1.125 +	first[data[idx].value] = data[idx].next;
   1.126 +      }
   1.127 +      if (data[idx].next != -1) {
   1.128 +	data[data[idx].next].prev = data[idx].prev;
   1.129 +      }
   1.130 +    }
   1.131 +
   1.132 +    void lace(int idx) {
   1.133 +      if ((int)first.size() <= data[idx].value) {
   1.134 +	first.resize(data[idx].value + 1, -1);
   1.135 +      }
   1.136 +      data[idx].next = first[data[idx].value];
   1.137 +      if (data[idx].next != -1) {
   1.138 +	data[data[idx].next].prev = idx;
   1.139 +      }
   1.140 +      first[data[idx].value] = idx;
   1.141 +      data[idx].prev = -1;
   1.142 +    }
   1.143 +
   1.144 +  public:
   1.145 +    /// \brief Insert a pair of item and priority into the heap.
   1.146 +    ///
   1.147 +    /// Adds \c p.first to the heap with priority \c p.second.
   1.148 +    /// \param p The pair to insert.
   1.149 +    void push(const Pair& p) {
   1.150 +      push(p.first, p.second);
   1.151 +    }
   1.152 +
   1.153 +    /// \brief Insert an item into the heap with the given priority.
   1.154 +    ///    
   1.155 +    /// Adds \c i to the heap with priority \c p. 
   1.156 +    /// \param i The item to insert.
   1.157 +    /// \param p The priority of the item.
   1.158 +    void push(const Item &i, const Prio &p) { 
   1.159 +      int idx = data.size();
   1.160 +      index[i] = idx;
   1.161 +      data.push_back(LinearItem(i, p));
   1.162 +      lace(idx);
   1.163 +      if (p < minimal) {
   1.164 +	minimal = p;
   1.165 +      }
   1.166 +    }
   1.167 +
   1.168 +    /// \brief Returns the item with minimum priority relative to \c Compare.
   1.169 +    ///
   1.170 +    /// This method returns the item with minimum priority relative to \c
   1.171 +    /// Compare.  
   1.172 +    /// \pre The heap must be nonempty.  
   1.173 +    Item top() const {
   1.174 +      while (first[minimal] == -1) {
   1.175 +	++minimal;
   1.176 +      }
   1.177 +      return data[first[minimal]].item;
   1.178 +    }
   1.179 +
   1.180 +    /// \brief Returns the minimum priority relative to \c Compare.
   1.181 +    ///
   1.182 +    /// It returns the minimum priority relative to \c Compare.
   1.183 +    /// \pre The heap must be nonempty.
   1.184 +    Prio prio() const {
   1.185 +      while (first[minimal] == -1) {
   1.186 +	++minimal;
   1.187 +      }
   1.188 +      return minimal;
   1.189 +    }
   1.190 +
   1.191 +    /// \brief Deletes the item with minimum priority relative to \c Compare.
   1.192 +    ///
   1.193 +    /// This method deletes the item with minimum priority relative to \c
   1.194 +    /// Compare from the heap.  
   1.195 +    /// \pre The heap must be non-empty.  
   1.196 +    void pop() {
   1.197 +      while (first[minimal] == -1) {
   1.198 +	++minimal;
   1.199 +      }
   1.200 +      int idx = first[minimal];
   1.201 +      index[data[idx].item] = -2;
   1.202 +      unlace(idx);
   1.203 +      relocate_last(idx);
   1.204 +    }
   1.205 +
   1.206 +    /// \brief Deletes \c i from the heap.
   1.207 +    ///
   1.208 +    /// This method deletes item \c i from the heap, if \c i was
   1.209 +    /// already stored in the heap.
   1.210 +    /// \param i The item to erase. 
   1.211 +    void erase(const Item &i) {
   1.212 +      int idx = index[i];
   1.213 +      index[data[idx].item] = -2;
   1.214 +      unlace(idx);
   1.215 +      relocate_last(idx);
   1.216 +    }
   1.217 +
   1.218 +    
   1.219 +    /// \brief Returns the priority of \c i.
   1.220 +    ///
   1.221 +    /// This function returns the priority of item \c i.  
   1.222 +    /// \pre \c i must be in the heap.
   1.223 +    /// \param i The item.
   1.224 +    Prio operator[](const Item &i) const {
   1.225 +      int idx = index[i];
   1.226 +      return data[idx].value;
   1.227 +    }
   1.228 +
   1.229 +    /// \brief \c i gets to the heap with priority \c p independently 
   1.230 +    /// if \c i was already there.
   1.231 +    ///
   1.232 +    /// This method calls \ref push(\c i, \c p) if \c i is not stored
   1.233 +    /// in the heap and sets the priority of \c i to \c p otherwise.
   1.234 +    /// \param i The item.
   1.235 +    /// \param p The priority.
   1.236 +    void set(const Item &i, const Prio &p) {
   1.237 +      int idx = index[i];
   1.238 +      if (idx < 0) {
   1.239 +	push(i,p);
   1.240 +      } else if (p > data[idx].value) {
   1.241 +	increase(i, p);
   1.242 +      } else {
   1.243 +	decrease(i, p);
   1.244 +      }
   1.245 +    }
   1.246 +
   1.247 +    /// \brief Decreases the priority of \c i to \c p.
   1.248 +
   1.249 +    /// This method decreases the priority of item \c i to \c p.
   1.250 +    /// \pre \c i must be stored in the heap with priority at least \c
   1.251 +    /// p relative to \c Compare.
   1.252 +    /// \param i The item.
   1.253 +    /// \param p The priority.
   1.254 +    void decrease(const Item &i, const Prio &p) {
   1.255 +      int idx = index[i];
   1.256 +      unlace(idx);
   1.257 +      data[idx].value = p;
   1.258 +      if (p < minimal) {
   1.259 +	minimal = p;
   1.260 +      }
   1.261 +      lace(idx);
   1.262 +    }
   1.263 +    
   1.264 +    /// \brief Increases the priority of \c i to \c p.
   1.265 +    ///
   1.266 +    /// This method sets the priority of item \c i to \c p. 
   1.267 +    /// \pre \c i must be stored in the heap with priority at most \c
   1.268 +    /// p relative to \c Compare.
   1.269 +    /// \param i The item.
   1.270 +    /// \param p The priority.
   1.271 +    void increase(const Item &i, const Prio &p) {
   1.272 +      int idx = index[i];
   1.273 +      unlace(idx);
   1.274 +      data[idx].value = p;
   1.275 +      lace(idx);
   1.276 +    }
   1.277 +
   1.278 +    /// \brief Returns if \c item is in, has already been in, or has 
   1.279 +    /// never been in the heap.
   1.280 +    ///
   1.281 +    /// This method returns PRE_HEAP if \c item has never been in the
   1.282 +    /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
   1.283 +    /// otherwise. In the latter case it is possible that \c item will
   1.284 +    /// get back to the heap again.
   1.285 +    /// \param i The item.
   1.286 +    state_enum state(const Item &i) const {
   1.287 +      int idx = index[i];
   1.288 +      if (idx >= 0) idx = 0;
   1.289 +      return state_enum(idx);
   1.290 +    }
   1.291 +
   1.292 +  private:
   1.293 +
   1.294 +    struct LinearItem {
   1.295 +      LinearItem(const Item& _item, int _value) 
   1.296 +	: item(_item), value(_value) {}
   1.297 +
   1.298 +      Item item;
   1.299 +      int value;
   1.300 +
   1.301 +      int prev, next;
   1.302 +    };
   1.303 +
   1.304 +    ItemIntMap& index;
   1.305 +    std::vector<int> first;
   1.306 +    std::vector<LinearItem> data;
   1.307 +    mutable int minimal;
   1.308 +
   1.309 +  }; // class LinearHeap
   1.310 +
   1.311 +
   1.312 +  template <typename _Item, typename _ItemIntMap>
   1.313 +  class LinearHeap<_Item, _ItemIntMap, false> {
   1.314 +
   1.315 +  public:
   1.316 +    typedef _Item Item;
   1.317 +    typedef int Prio;
   1.318 +    typedef std::pair<Item, Prio> Pair;
   1.319 +    typedef _ItemIntMap ItemIntMap;
   1.320 +
   1.321 +    enum state_enum {
   1.322 +      IN_HEAP = 0,
   1.323 +      PRE_HEAP = -1,
   1.324 +      POST_HEAP = -2
   1.325 +    };
   1.326 +
   1.327 +  public:
   1.328 +
   1.329 +    explicit LinearHeap(ItemIntMap &_index) : index(_index), maximal(-1) {}
   1.330 +
   1.331 +    int size() const { return data.size(); }
   1.332 +    bool empty() const { return data.empty(); }
   1.333 +
   1.334 +    void clear() { 
   1.335 +      for (int i = 0; i < (int)data.size(); ++i) {
   1.336 +	index[data[i].item] = -2;
   1.337 +      }
   1.338 +      data.clear(); first.clear(); maximal = -1; 
   1.339 +    }
   1.340 +
   1.341 +  private:
   1.342 +
   1.343 +    void relocate_last(int idx) {
   1.344 +      if (idx + 1 != (int)data.size()) {
   1.345 +	data[idx] = data.back();
   1.346 +	if (data[idx].prev != -1) {
   1.347 +	  data[data[idx].prev].next = idx;
   1.348 +	} else {
   1.349 +	  first[data[idx].value] = idx;
   1.350 +	}
   1.351 +	if (data[idx].next != -1) {
   1.352 +	  data[data[idx].next].prev = idx;
   1.353 +	}
   1.354 +	index[data[idx].item] = idx;
   1.355 +      }
   1.356 +      data.pop_back();
   1.357 +    }
   1.358 +
   1.359 +    void unlace(int idx) {
   1.360 +      if (data[idx].prev != -1) {
   1.361 +	data[data[idx].prev].next = data[idx].next;
   1.362 +      } else {
   1.363 +	first[data[idx].value] = data[idx].next;
   1.364 +      }
   1.365 +      if (data[idx].next != -1) {
   1.366 +	data[data[idx].next].prev = data[idx].prev;
   1.367 +      }
   1.368 +    }
   1.369 +
   1.370 +    void lace(int idx) {
   1.371 +      if ((int)first.size() <= data[idx].value) {
   1.372 +	first.resize(data[idx].value + 1, -1);
   1.373 +      }
   1.374 +      data[idx].next = first[data[idx].value];
   1.375 +      if (data[idx].next != -1) {
   1.376 +	data[data[idx].next].prev = idx;
   1.377 +      }
   1.378 +      first[data[idx].value] = idx;
   1.379 +      data[idx].prev = -1;
   1.380 +    }
   1.381 +
   1.382 +  public:
   1.383 +
   1.384 +    void push(const Pair& p) {
   1.385 +      push(p.first, p.second);
   1.386 +    }
   1.387 +
   1.388 +    void push(const Item &i, const Prio &p) { 
   1.389 +      int idx = data.size();
   1.390 +      index[i] = idx;
   1.391 +      data.push_back(LinearItem(i, p));
   1.392 +      lace(idx);
   1.393 +      if (data[idx].value > maximal) {
   1.394 +	maximal = data[idx].value;
   1.395 +      }
   1.396 +    }
   1.397 +
   1.398 +    Item top() const {
   1.399 +      while (first[maximal] == -1) {
   1.400 +	--maximal;
   1.401 +      }
   1.402 +      return data[first[maximal]].item;
   1.403 +    }
   1.404 +
   1.405 +    Prio prio() const {
   1.406 +      while (first[maximal] == -1) {
   1.407 +	--maximal;
   1.408 +      }
   1.409 +      return maximal;
   1.410 +    }
   1.411 +
   1.412 +    void pop() {
   1.413 +      while (first[maximal] == -1) {
   1.414 +	--maximal;
   1.415 +      }
   1.416 +      int idx = first[maximal];
   1.417 +      index[data[idx].item] = -2;
   1.418 +      unlace(idx);
   1.419 +      relocate_last(idx);
   1.420 +    }
   1.421 +
   1.422 +    void erase(const Item &i) {
   1.423 +      int idx = index[i];
   1.424 +      index[data[idx].item] = -2;
   1.425 +      unlace(idx);
   1.426 +      relocate_last(idx);
   1.427 +    }
   1.428 +
   1.429 +    Prio operator[](const Item &i) const {
   1.430 +      int idx = index[i];
   1.431 +      return data[idx].value;
   1.432 +    }
   1.433 +
   1.434 +    void set(const Item &i, const Prio &p) {
   1.435 +      int idx = index[i];
   1.436 +      if (idx < 0) {
   1.437 +	push(i,p);
   1.438 +      } else if (p > data[idx].value) {
   1.439 +	decrease(i, p);
   1.440 +      } else {
   1.441 +	increase(i, p);
   1.442 +      }
   1.443 +    }
   1.444 +
   1.445 +    void decrease(const Item &i, const Prio &p) {
   1.446 +      int idx = index[i];
   1.447 +      unlace(idx);
   1.448 +      data[idx].value = p;
   1.449 +      if (p > maximal) {
   1.450 +	maximal = p;
   1.451 +      }
   1.452 +      lace(idx);
   1.453 +    }
   1.454 +    
   1.455 +    void increase(const Item &i, const Prio &p) {
   1.456 +      int idx = index[i];
   1.457 +      unlace(idx);
   1.458 +      data[idx].value = p;
   1.459 +      lace(idx);
   1.460 +    }
   1.461 +
   1.462 +    state_enum state(const Item &i) const {
   1.463 +      int idx = index[i];
   1.464 +      if (idx >= 0) idx = 0;
   1.465 +      return state_enum(idx);
   1.466 +    }
   1.467 +
   1.468 +  private:
   1.469 +
   1.470 +    struct LinearItem {
   1.471 +      LinearItem(const Item& _item, int _value) 
   1.472 +	: item(_item), value(_value) {}
   1.473 +
   1.474 +      Item item;
   1.475 +      int value;
   1.476 +
   1.477 +      int prev, next;
   1.478 +    };
   1.479 +
   1.480 +    ItemIntMap& index;
   1.481 +    std::vector<int> first;
   1.482 +    std::vector<LinearItem> data;
   1.483 +    mutable int maximal;
   1.484 +
   1.485 +  }; // class LinearHeap
   1.486 +
   1.487 +}
   1.488 +  
   1.489 +#endif