lemon/linear_heap.h
author hegyi
Mon, 21 Nov 2005 18:03:20 +0000
changeset 1823 cb082cdf3667
parent 1724 b20777184ba8
child 1834 0a14e1ae45a1
permissions -rw-r--r--
NewMapWin has become Dialog instead of Window. Therefore it is created dynamically, when there is need for it, instead of keeping one instance in memory. This solution is slower, but more correct than before.
deba@1724
     1
/* -*- C++ -*-
deba@1724
     2
 * lemon/linear_heap.h - Part of LEMON, a generic C++ optimization library
deba@1724
     3
 *
deba@1724
     4
 * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
deba@1724
     5
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@1724
     6
 *
deba@1724
     7
 * Permission to use, modify and distribute this software is granted
deba@1724
     8
 * provided that this copyright notice appears in all copies. For
deba@1724
     9
 * precise terms see the accompanying LICENSE file.
deba@1724
    10
 *
deba@1724
    11
 * This software is provided "AS IS" with no warranty of any kind,
deba@1724
    12
 * express or implied, and with no claim as to its suitability for any
deba@1724
    13
 * purpose.
deba@1724
    14
 *
deba@1724
    15
 */
deba@1724
    16
deba@1724
    17
#ifndef LEMON_LINEAR_HEAP_H
deba@1724
    18
#define LEMON_LINEAR_HEAP_H
deba@1724
    19
deba@1724
    20
///\ingroup auxdat
deba@1724
    21
///\file
deba@1724
    22
///\brief Binary Heap implementation.
deba@1724
    23
deba@1724
    24
#include <vector>
deba@1724
    25
#include <utility>
deba@1724
    26
#include <functional>
deba@1724
    27
deba@1724
    28
namespace lemon {
deba@1724
    29
deba@1724
    30
  /// \addtogroup auxdat
deba@1724
    31
  /// @{
deba@1724
    32
deba@1724
    33
  /// \brief A Linear Heap implementation.
deba@1724
    34
  ///
deba@1724
    35
  /// This class implements the \e linear \e heap data structure. A \e heap
deba@1724
    36
  /// is a data structure for storing items with specified values called \e
deba@1724
    37
  /// priorities in such a way that finding the item with minimum priority is
deba@1724
    38
  /// efficient. The linear heap is very simple implementation, it can store
deba@1724
    39
  /// only integer priorities and it stores for each priority in the [0..C]
deba@1724
    40
  /// range a list of items. So it should be used only when the priorities
deba@1724
    41
  /// are small. It is not intended to use as dijkstra heap.
deba@1724
    42
  ///
deba@1724
    43
  /// \param _Item Type of the items to be stored.  
deba@1724
    44
  /// \param _ItemIntMap A read and writable Item int map, used internally
deba@1724
    45
  /// to handle the cross references.
deba@1724
    46
  /// \param minimize If the given parameter is true then the heap gives back
deba@1724
    47
  /// the lowest priority. 
deba@1724
    48
  template <typename _Item, typename _ItemIntMap, bool minimize = true >
deba@1724
    49
  class LinearHeap {
deba@1724
    50
deba@1724
    51
  public:
deba@1724
    52
    typedef _Item Item;
deba@1724
    53
    typedef int Prio;
deba@1724
    54
    typedef std::pair<Item, Prio> Pair;
deba@1724
    55
    typedef _ItemIntMap ItemIntMap;
deba@1724
    56
deba@1724
    57
    /// \brief Type to represent the items states.
deba@1724
    58
    ///
deba@1724
    59
    /// Each Item element have a state associated to it. It may be "in heap",
deba@1724
    60
    /// "pre heap" or "post heap". The latter two are indifferent from the
deba@1724
    61
    /// heap's point of view, but may be useful to the user.
deba@1724
    62
    ///
deba@1724
    63
    /// The ItemIntMap \e should be initialized in such way that it maps
deba@1724
    64
    /// PRE_HEAP (-1) to any element to be put in the heap...
deba@1724
    65
    enum state_enum {
deba@1724
    66
      IN_HEAP = 0,
deba@1724
    67
      PRE_HEAP = -1,
deba@1724
    68
      POST_HEAP = -2
deba@1724
    69
    };
deba@1724
    70
deba@1724
    71
  public:
deba@1724
    72
    /// \brief The constructor.
deba@1724
    73
    ///
deba@1724
    74
    /// The constructor.
deba@1724
    75
    /// \param _index should be given to the constructor, since it is used
deba@1724
    76
    /// internally to handle the cross references. The value of the map
deba@1724
    77
    /// should be PRE_HEAP (-1) for each element.
deba@1724
    78
    explicit LinearHeap(ItemIntMap &_index) : index(_index), minimal(0) {}
deba@1724
    79
    
deba@1724
    80
    /// The number of items stored in the heap.
deba@1724
    81
    ///
deba@1724
    82
    /// \brief Returns the number of items stored in the heap.
deba@1724
    83
    int size() const { return data.size(); }
deba@1724
    84
    
deba@1724
    85
    /// \brief Checks if the heap stores no items.
deba@1724
    86
    ///
deba@1724
    87
    /// Returns \c true if and only if the heap stores no items.
deba@1724
    88
    bool empty() const { return data.empty(); }
deba@1724
    89
deba@1724
    90
    /// \brief Make empty this heap.
deba@1724
    91
    /// 
deba@1724
    92
    /// Make empty this heap.
deba@1724
    93
    void clear() { 
deba@1724
    94
      for (int i = 0; i < (int)data.size(); ++i) {
deba@1724
    95
	index[data[i].item] = -2;
deba@1724
    96
      }
deba@1724
    97
      data.clear(); first.clear(); minimal = 0;
deba@1724
    98
    }
deba@1724
    99
deba@1724
   100
  private:
deba@1724
   101
deba@1724
   102
    void relocate_last(int idx) {
deba@1724
   103
      if (idx + 1 < (int)data.size()) {
deba@1724
   104
	data[idx] = data.back();
deba@1724
   105
	if (data[idx].prev != -1) {
deba@1724
   106
	  data[data[idx].prev].next = idx;
deba@1724
   107
	} else {
deba@1724
   108
	  first[data[idx].value] = idx;
deba@1724
   109
	}
deba@1724
   110
	if (data[idx].next != -1) {
deba@1724
   111
	  data[data[idx].next].prev = idx;
deba@1724
   112
	}
deba@1724
   113
	index[data[idx].item] = idx;
deba@1724
   114
      }
deba@1724
   115
      data.pop_back();
deba@1724
   116
    }
deba@1724
   117
deba@1724
   118
    void unlace(int idx) {
deba@1724
   119
      if (data[idx].prev != -1) {
deba@1724
   120
	data[data[idx].prev].next = data[idx].next;
deba@1724
   121
      } else {
deba@1724
   122
	first[data[idx].value] = data[idx].next;
deba@1724
   123
      }
deba@1724
   124
      if (data[idx].next != -1) {
deba@1724
   125
	data[data[idx].next].prev = data[idx].prev;
deba@1724
   126
      }
deba@1724
   127
    }
deba@1724
   128
deba@1724
   129
    void lace(int idx) {
deba@1724
   130
      if ((int)first.size() <= data[idx].value) {
deba@1724
   131
	first.resize(data[idx].value + 1, -1);
deba@1724
   132
      }
deba@1724
   133
      data[idx].next = first[data[idx].value];
deba@1724
   134
      if (data[idx].next != -1) {
deba@1724
   135
	data[data[idx].next].prev = idx;
deba@1724
   136
      }
deba@1724
   137
      first[data[idx].value] = idx;
deba@1724
   138
      data[idx].prev = -1;
deba@1724
   139
    }
deba@1724
   140
deba@1724
   141
  public:
deba@1724
   142
    /// \brief Insert a pair of item and priority into the heap.
deba@1724
   143
    ///
deba@1724
   144
    /// Adds \c p.first to the heap with priority \c p.second.
deba@1724
   145
    /// \param p The pair to insert.
deba@1724
   146
    void push(const Pair& p) {
deba@1724
   147
      push(p.first, p.second);
deba@1724
   148
    }
deba@1724
   149
deba@1724
   150
    /// \brief Insert an item into the heap with the given priority.
deba@1724
   151
    ///    
deba@1724
   152
    /// Adds \c i to the heap with priority \c p. 
deba@1724
   153
    /// \param i The item to insert.
deba@1724
   154
    /// \param p The priority of the item.
deba@1724
   155
    void push(const Item &i, const Prio &p) { 
deba@1724
   156
      int idx = data.size();
deba@1724
   157
      index[i] = idx;
deba@1724
   158
      data.push_back(LinearItem(i, p));
deba@1724
   159
      lace(idx);
deba@1724
   160
      if (p < minimal) {
deba@1724
   161
	minimal = p;
deba@1724
   162
      }
deba@1724
   163
    }
deba@1724
   164
deba@1758
   165
    /// \brief Returns the item with minimum priority.
deba@1724
   166
    ///
deba@1758
   167
    /// This method returns the item with minimum priority.
deba@1724
   168
    /// \pre The heap must be nonempty.  
deba@1724
   169
    Item top() const {
deba@1724
   170
      while (first[minimal] == -1) {
deba@1724
   171
	++minimal;
deba@1724
   172
      }
deba@1724
   173
      return data[first[minimal]].item;
deba@1724
   174
    }
deba@1724
   175
deba@1758
   176
    /// \brief Returns the minimum priority.
deba@1724
   177
    ///
deba@1758
   178
    /// It returns the minimum priority.
deba@1724
   179
    /// \pre The heap must be nonempty.
deba@1724
   180
    Prio prio() const {
deba@1724
   181
      while (first[minimal] == -1) {
deba@1724
   182
	++minimal;
deba@1724
   183
      }
deba@1724
   184
      return minimal;
deba@1724
   185
    }
deba@1724
   186
deba@1758
   187
    /// \brief Deletes the item with minimum priority.
deba@1724
   188
    ///
deba@1758
   189
    /// This method deletes the item with minimum priority from the heap.  
deba@1724
   190
    /// \pre The heap must be non-empty.  
deba@1724
   191
    void pop() {
deba@1724
   192
      while (first[minimal] == -1) {
deba@1724
   193
	++minimal;
deba@1724
   194
      }
deba@1724
   195
      int idx = first[minimal];
deba@1724
   196
      index[data[idx].item] = -2;
deba@1724
   197
      unlace(idx);
deba@1724
   198
      relocate_last(idx);
deba@1724
   199
    }
deba@1724
   200
deba@1724
   201
    /// \brief Deletes \c i from the heap.
deba@1724
   202
    ///
deba@1724
   203
    /// This method deletes item \c i from the heap, if \c i was
deba@1724
   204
    /// already stored in the heap.
deba@1724
   205
    /// \param i The item to erase. 
deba@1724
   206
    void erase(const Item &i) {
deba@1724
   207
      int idx = index[i];
deba@1724
   208
      index[data[idx].item] = -2;
deba@1724
   209
      unlace(idx);
deba@1724
   210
      relocate_last(idx);
deba@1724
   211
    }
deba@1724
   212
deba@1724
   213
    
deba@1724
   214
    /// \brief Returns the priority of \c i.
deba@1724
   215
    ///
deba@1724
   216
    /// This function returns the priority of item \c i.  
deba@1724
   217
    /// \pre \c i must be in the heap.
deba@1724
   218
    /// \param i The item.
deba@1724
   219
    Prio operator[](const Item &i) const {
deba@1724
   220
      int idx = index[i];
deba@1724
   221
      return data[idx].value;
deba@1724
   222
    }
deba@1724
   223
deba@1724
   224
    /// \brief \c i gets to the heap with priority \c p independently 
deba@1724
   225
    /// if \c i was already there.
deba@1724
   226
    ///
deba@1724
   227
    /// This method calls \ref push(\c i, \c p) if \c i is not stored
deba@1724
   228
    /// in the heap and sets the priority of \c i to \c p otherwise.
deba@1724
   229
    /// \param i The item.
deba@1724
   230
    /// \param p The priority.
deba@1724
   231
    void set(const Item &i, const Prio &p) {
deba@1724
   232
      int idx = index[i];
deba@1724
   233
      if (idx < 0) {
deba@1724
   234
	push(i,p);
deba@1724
   235
      } else if (p > data[idx].value) {
deba@1724
   236
	increase(i, p);
deba@1724
   237
      } else {
deba@1724
   238
	decrease(i, p);
deba@1724
   239
      }
deba@1724
   240
    }
deba@1724
   241
deba@1724
   242
    /// \brief Decreases the priority of \c i to \c p.
deba@1724
   243
deba@1724
   244
    /// This method decreases the priority of item \c i to \c p.
deba@1724
   245
    /// \pre \c i must be stored in the heap with priority at least \c
deba@1724
   246
    /// p relative to \c Compare.
deba@1724
   247
    /// \param i The item.
deba@1724
   248
    /// \param p The priority.
deba@1724
   249
    void decrease(const Item &i, const Prio &p) {
deba@1724
   250
      int idx = index[i];
deba@1724
   251
      unlace(idx);
deba@1724
   252
      data[idx].value = p;
deba@1724
   253
      if (p < minimal) {
deba@1724
   254
	minimal = p;
deba@1724
   255
      }
deba@1724
   256
      lace(idx);
deba@1724
   257
    }
deba@1724
   258
    
deba@1724
   259
    /// \brief Increases the priority of \c i to \c p.
deba@1724
   260
    ///
deba@1724
   261
    /// This method sets the priority of item \c i to \c p. 
deba@1724
   262
    /// \pre \c i must be stored in the heap with priority at most \c
deba@1724
   263
    /// p relative to \c Compare.
deba@1724
   264
    /// \param i The item.
deba@1724
   265
    /// \param p The priority.
deba@1724
   266
    void increase(const Item &i, const Prio &p) {
deba@1724
   267
      int idx = index[i];
deba@1724
   268
      unlace(idx);
deba@1724
   269
      data[idx].value = p;
deba@1724
   270
      lace(idx);
deba@1724
   271
    }
deba@1724
   272
deba@1724
   273
    /// \brief Returns if \c item is in, has already been in, or has 
deba@1724
   274
    /// never been in the heap.
deba@1724
   275
    ///
deba@1724
   276
    /// This method returns PRE_HEAP if \c item has never been in the
deba@1724
   277
    /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
deba@1724
   278
    /// otherwise. In the latter case it is possible that \c item will
deba@1724
   279
    /// get back to the heap again.
deba@1724
   280
    /// \param i The item.
deba@1724
   281
    state_enum state(const Item &i) const {
deba@1724
   282
      int idx = index[i];
deba@1724
   283
      if (idx >= 0) idx = 0;
deba@1724
   284
      return state_enum(idx);
deba@1724
   285
    }
deba@1724
   286
deba@1724
   287
  private:
deba@1724
   288
deba@1724
   289
    struct LinearItem {
deba@1724
   290
      LinearItem(const Item& _item, int _value) 
deba@1724
   291
	: item(_item), value(_value) {}
deba@1724
   292
deba@1724
   293
      Item item;
deba@1724
   294
      int value;
deba@1724
   295
deba@1724
   296
      int prev, next;
deba@1724
   297
    };
deba@1724
   298
deba@1724
   299
    ItemIntMap& index;
deba@1724
   300
    std::vector<int> first;
deba@1724
   301
    std::vector<LinearItem> data;
deba@1724
   302
    mutable int minimal;
deba@1724
   303
deba@1724
   304
  }; // class LinearHeap
deba@1724
   305
deba@1724
   306
deba@1724
   307
  template <typename _Item, typename _ItemIntMap>
deba@1724
   308
  class LinearHeap<_Item, _ItemIntMap, false> {
deba@1724
   309
deba@1724
   310
  public:
deba@1724
   311
    typedef _Item Item;
deba@1724
   312
    typedef int Prio;
deba@1724
   313
    typedef std::pair<Item, Prio> Pair;
deba@1724
   314
    typedef _ItemIntMap ItemIntMap;
deba@1724
   315
deba@1724
   316
    enum state_enum {
deba@1724
   317
      IN_HEAP = 0,
deba@1724
   318
      PRE_HEAP = -1,
deba@1724
   319
      POST_HEAP = -2
deba@1724
   320
    };
deba@1724
   321
deba@1724
   322
  public:
deba@1724
   323
deba@1724
   324
    explicit LinearHeap(ItemIntMap &_index) : index(_index), maximal(-1) {}
deba@1724
   325
deba@1724
   326
    int size() const { return data.size(); }
deba@1724
   327
    bool empty() const { return data.empty(); }
deba@1724
   328
deba@1724
   329
    void clear() { 
deba@1724
   330
      for (int i = 0; i < (int)data.size(); ++i) {
deba@1724
   331
	index[data[i].item] = -2;
deba@1724
   332
      }
deba@1724
   333
      data.clear(); first.clear(); maximal = -1; 
deba@1724
   334
    }
deba@1724
   335
deba@1724
   336
  private:
deba@1724
   337
deba@1724
   338
    void relocate_last(int idx) {
deba@1724
   339
      if (idx + 1 != (int)data.size()) {
deba@1724
   340
	data[idx] = data.back();
deba@1724
   341
	if (data[idx].prev != -1) {
deba@1724
   342
	  data[data[idx].prev].next = idx;
deba@1724
   343
	} else {
deba@1724
   344
	  first[data[idx].value] = idx;
deba@1724
   345
	}
deba@1724
   346
	if (data[idx].next != -1) {
deba@1724
   347
	  data[data[idx].next].prev = idx;
deba@1724
   348
	}
deba@1724
   349
	index[data[idx].item] = idx;
deba@1724
   350
      }
deba@1724
   351
      data.pop_back();
deba@1724
   352
    }
deba@1724
   353
deba@1724
   354
    void unlace(int idx) {
deba@1724
   355
      if (data[idx].prev != -1) {
deba@1724
   356
	data[data[idx].prev].next = data[idx].next;
deba@1724
   357
      } else {
deba@1724
   358
	first[data[idx].value] = data[idx].next;
deba@1724
   359
      }
deba@1724
   360
      if (data[idx].next != -1) {
deba@1724
   361
	data[data[idx].next].prev = data[idx].prev;
deba@1724
   362
      }
deba@1724
   363
    }
deba@1724
   364
deba@1724
   365
    void lace(int idx) {
deba@1724
   366
      if ((int)first.size() <= data[idx].value) {
deba@1724
   367
	first.resize(data[idx].value + 1, -1);
deba@1724
   368
      }
deba@1724
   369
      data[idx].next = first[data[idx].value];
deba@1724
   370
      if (data[idx].next != -1) {
deba@1724
   371
	data[data[idx].next].prev = idx;
deba@1724
   372
      }
deba@1724
   373
      first[data[idx].value] = idx;
deba@1724
   374
      data[idx].prev = -1;
deba@1724
   375
    }
deba@1724
   376
deba@1724
   377
  public:
deba@1724
   378
deba@1724
   379
    void push(const Pair& p) {
deba@1724
   380
      push(p.first, p.second);
deba@1724
   381
    }
deba@1724
   382
deba@1724
   383
    void push(const Item &i, const Prio &p) { 
deba@1724
   384
      int idx = data.size();
deba@1724
   385
      index[i] = idx;
deba@1724
   386
      data.push_back(LinearItem(i, p));
deba@1724
   387
      lace(idx);
deba@1724
   388
      if (data[idx].value > maximal) {
deba@1724
   389
	maximal = data[idx].value;
deba@1724
   390
      }
deba@1724
   391
    }
deba@1724
   392
deba@1724
   393
    Item top() const {
deba@1724
   394
      while (first[maximal] == -1) {
deba@1724
   395
	--maximal;
deba@1724
   396
      }
deba@1724
   397
      return data[first[maximal]].item;
deba@1724
   398
    }
deba@1724
   399
deba@1724
   400
    Prio prio() const {
deba@1724
   401
      while (first[maximal] == -1) {
deba@1724
   402
	--maximal;
deba@1724
   403
      }
deba@1724
   404
      return maximal;
deba@1724
   405
    }
deba@1724
   406
deba@1724
   407
    void pop() {
deba@1724
   408
      while (first[maximal] == -1) {
deba@1724
   409
	--maximal;
deba@1724
   410
      }
deba@1724
   411
      int idx = first[maximal];
deba@1724
   412
      index[data[idx].item] = -2;
deba@1724
   413
      unlace(idx);
deba@1724
   414
      relocate_last(idx);
deba@1724
   415
    }
deba@1724
   416
deba@1724
   417
    void erase(const Item &i) {
deba@1724
   418
      int idx = index[i];
deba@1724
   419
      index[data[idx].item] = -2;
deba@1724
   420
      unlace(idx);
deba@1724
   421
      relocate_last(idx);
deba@1724
   422
    }
deba@1724
   423
deba@1724
   424
    Prio operator[](const Item &i) const {
deba@1724
   425
      int idx = index[i];
deba@1724
   426
      return data[idx].value;
deba@1724
   427
    }
deba@1724
   428
deba@1724
   429
    void set(const Item &i, const Prio &p) {
deba@1724
   430
      int idx = index[i];
deba@1724
   431
      if (idx < 0) {
deba@1724
   432
	push(i,p);
deba@1724
   433
      } else if (p > data[idx].value) {
deba@1724
   434
	decrease(i, p);
deba@1724
   435
      } else {
deba@1724
   436
	increase(i, p);
deba@1724
   437
      }
deba@1724
   438
    }
deba@1724
   439
deba@1724
   440
    void decrease(const Item &i, const Prio &p) {
deba@1724
   441
      int idx = index[i];
deba@1724
   442
      unlace(idx);
deba@1724
   443
      data[idx].value = p;
deba@1724
   444
      if (p > maximal) {
deba@1724
   445
	maximal = p;
deba@1724
   446
      }
deba@1724
   447
      lace(idx);
deba@1724
   448
    }
deba@1724
   449
    
deba@1724
   450
    void increase(const Item &i, const Prio &p) {
deba@1724
   451
      int idx = index[i];
deba@1724
   452
      unlace(idx);
deba@1724
   453
      data[idx].value = p;
deba@1724
   454
      lace(idx);
deba@1724
   455
    }
deba@1724
   456
deba@1724
   457
    state_enum state(const Item &i) const {
deba@1724
   458
      int idx = index[i];
deba@1724
   459
      if (idx >= 0) idx = 0;
deba@1724
   460
      return state_enum(idx);
deba@1724
   461
    }
deba@1724
   462
deba@1724
   463
  private:
deba@1724
   464
deba@1724
   465
    struct LinearItem {
deba@1724
   466
      LinearItem(const Item& _item, int _value) 
deba@1724
   467
	: item(_item), value(_value) {}
deba@1724
   468
deba@1724
   469
      Item item;
deba@1724
   470
      int value;
deba@1724
   471
deba@1724
   472
      int prev, next;
deba@1724
   473
    };
deba@1724
   474
deba@1724
   475
    ItemIntMap& index;
deba@1724
   476
    std::vector<int> first;
deba@1724
   477
    std::vector<LinearItem> data;
deba@1724
   478
    mutable int maximal;
deba@1724
   479
deba@1724
   480
  }; // class LinearHeap
deba@1724
   481
deba@1724
   482
}
deba@1724
   483
  
deba@1724
   484
#endif