gravatar
kpeter (Peter Kovacs)
kpeter@inf.elte.hu
Much faster implementation for BinomHeap (#301)
0 1 0
default
1 file changed with 88 insertions and 157 deletions:
↑ Collapse diff ↑
Ignore white space 48 line context
... ...
@@ -58,51 +58,51 @@
58 58
    /// Type of the item-int map.
59 59
    typedef IM ItemIntMap;
60 60
    /// Type of the priorities.
61 61
    typedef PR Prio;
62 62
    /// Type of the items stored in the heap.
63 63
    typedef typename ItemIntMap::Key Item;
64 64
    /// Functor type for comparing the priorities.
65 65
    typedef CMP Compare;
66 66

	
67 67
    /// \brief Type to represent the states of the items.
68 68
    ///
69 69
    /// Each item has a state associated to it. It can be "in heap",
70 70
    /// "pre-heap" or "post-heap". The latter two are indifferent from the
71 71
    /// heap's point of view, but may be useful to the user.
72 72
    ///
73 73
    /// The item-int map must be initialized in such way that it assigns
74 74
    /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
75 75
    enum State {
76 76
      IN_HEAP = 0,    ///< = 0.
77 77
      PRE_HEAP = -1,  ///< = -1.
78 78
      POST_HEAP = -2  ///< = -2.
79 79
    };
80 80

	
81 81
  private:
82
    class store;
82
    class Store;
83 83

	
84
    std::vector<store> _data;
84
    std::vector<Store> _data;
85 85
    int _min, _head;
86 86
    ItemIntMap &_iim;
87 87
    Compare _comp;
88 88
    int _num_items;
89 89

	
90 90
  public:
91 91
    /// \brief Constructor.
92 92
    ///
93 93
    /// Constructor.
94 94
    /// \param map A map that assigns \c int values to the items.
95 95
    /// It is used internally to handle the cross references.
96 96
    /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
97 97
    explicit BinomHeap(ItemIntMap &map)
98 98
      : _min(0), _head(-1), _iim(map), _num_items(0) {}
99 99

	
100 100
    /// \brief Constructor.
101 101
    ///
102 102
    /// Constructor.
103 103
    /// \param map A map that assigns \c int values to the items.
104 104
    /// It is used internally to handle the cross references.
105 105
    /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
106 106
    /// \param comp The function object used for comparing the priorities.
107 107
    BinomHeap(ItemIntMap &map, const Compare &comp)
108 108
      : _min(0), _head(-1), _iim(map), _comp(comp), _num_items(0) {}
... ...
@@ -135,215 +135,162 @@
135 135
    /// already stored in the heap. Otherwise it inserts the given
136 136
    /// item into the heap with the given priority.
137 137
    /// \param item The item.
138 138
    /// \param value The priority.
139 139
    void set (const Item& item, const Prio& value) {
140 140
      int i=_iim[item];
141 141
      if ( i >= 0 && _data[i].in ) {
142 142
        if ( _comp(value, _data[i].prio) ) decrease(item, value);
143 143
        if ( _comp(_data[i].prio, value) ) increase(item, value);
144 144
      } else push(item, value);
145 145
    }
146 146

	
147 147
    /// \brief Insert an item into the heap with the given priority.
148 148
    ///
149 149
    /// This function inserts the given item into the heap with the
150 150
    /// given priority.
151 151
    /// \param item The item to insert.
152 152
    /// \param value The priority of the item.
153 153
    /// \pre \e item must not be stored in the heap.
154 154
    void push (const Item& item, const Prio& value) {
155 155
      int i=_iim[item];
156 156
      if ( i<0 ) {
157 157
        int s=_data.size();
158 158
        _iim.set( item,s );
159
        store st;
159
        Store st;
160 160
        st.name=item;
161
        st.prio=value;
161 162
        _data.push_back(st);
162 163
        i=s;
163 164
      }
164 165
      else {
165 166
        _data[i].parent=_data[i].right_neighbor=_data[i].child=-1;
166 167
        _data[i].degree=0;
167 168
        _data[i].in=true;
169
        _data[i].prio=value;
168 170
      }
169
      _data[i].prio=value;
170 171

	
171
      if( 0==_num_items ) { _head=i; _min=i; }
172
      else { merge(i); }
173

	
174
      _min = findMin();
175

	
172
      if( 0==_num_items ) {
173
        _head=i;
174
        _min=i;
175
      } else {
176
        merge(i);
177
        if( _comp(_data[i].prio, _data[_min].prio) ) _min=i;
178
      }
176 179
      ++_num_items;
177 180
    }
178 181

	
179 182
    /// \brief Return the item having minimum priority.
180 183
    ///
181 184
    /// This function returns the item having minimum priority.
182 185
    /// \pre The heap must be non-empty.
183 186
    Item top() const { return _data[_min].name; }
184 187

	
185 188
    /// \brief The minimum priority.
186 189
    ///
187 190
    /// This function returns the minimum priority.
188 191
    /// \pre The heap must be non-empty.
189 192
    Prio prio() const { return _data[_min].prio; }
190 193

	
191 194
    /// \brief The priority of the given item.
192 195
    ///
193 196
    /// This function returns the priority of the given item.
194 197
    /// \param item The item.
195 198
    /// \pre \e item must be in the heap.
196 199
    const Prio& operator[](const Item& item) const {
197 200
      return _data[_iim[item]].prio;
198 201
    }
199 202

	
200 203
    /// \brief Remove the item having minimum priority.
201 204
    ///
202 205
    /// This function removes the item having minimum priority.
203 206
    /// \pre The heap must be non-empty.
204 207
    void pop() {
205 208
      _data[_min].in=false;
206 209

	
207 210
      int head_child=-1;
208 211
      if ( _data[_min].child!=-1 ) {
209 212
        int child=_data[_min].child;
210 213
        int neighb;
211
        int prev=-1;
212 214
        while( child!=-1 ) {
213 215
          neighb=_data[child].right_neighbor;
214 216
          _data[child].parent=-1;
215
          _data[child].right_neighbor=prev;
217
          _data[child].right_neighbor=head_child;
216 218
          head_child=child;
217
          prev=child;
218 219
          child=neighb;
219 220
        }
220 221
      }
221 222

	
222
      // The first case is that there are only one root.
223
      if ( -1==_data[_head].right_neighbor ) {
223
      if ( _data[_head].right_neighbor==-1 ) {
224
        // there was only one root
224 225
        _head=head_child;
225 226
      }
226
      // The case where there are more roots.
227 227
      else {
228
        // there were more roots
228 229
        if( _head!=_min )  { unlace(_min); }
229 230
        else { _head=_data[_head].right_neighbor; }
230

	
231 231
        merge(head_child);
232 232
      }
233 233
      _min=findMin();
234 234
      --_num_items;
235 235
    }
236 236

	
237 237
    /// \brief Remove the given item from the heap.
238 238
    ///
239 239
    /// This function removes the given item from the heap if it is
240 240
    /// already stored.
241 241
    /// \param item The item to delete.
242 242
    /// \pre \e item must be in the heap.
243 243
    void erase (const Item& item) {
244 244
      int i=_iim[item];
245 245
      if ( i >= 0 && _data[i].in ) {
246 246
        decrease( item, _data[_min].prio-1 );
247 247
        pop();
248 248
      }
249 249
    }
250 250

	
251 251
    /// \brief Decrease the priority of an item to the given value.
252 252
    ///
253 253
    /// This function decreases the priority of an item to the given value.
254 254
    /// \param item The item.
255 255
    /// \param value The priority.
256 256
    /// \pre \e item must be stored in the heap with priority at least \e value.
257 257
    void decrease (Item item, const Prio& value) {
258 258
      int i=_iim[item];
259

	
260
      if( _comp( value,_data[i].prio ) ) {
261
        _data[i].prio=value;
262

	
263
        int p_loc=_data[i].parent, loc=i;
264
        int parent, child, neighb;
265

	
266
        while( -1!=p_loc && _comp(_data[loc].prio,_data[p_loc].prio) ) {
267

	
268
          // parent set for other loc_child
269
          child=_data[loc].child;
270
          while( -1!=child ) {
271
            _data[child].parent=p_loc;
272
            child=_data[child].right_neighbor;
273
          }
274

	
275
          // parent set for other p_loc_child
276
          child=_data[p_loc].child;
277
          while( -1!=child ) {
278
            _data[child].parent=loc;
279
            child=_data[child].right_neighbor;
280
          }
281

	
282
          child=_data[p_loc].child;
283
          _data[p_loc].child=_data[loc].child;
284
          if( child==loc )
285
            child=p_loc;
286
          _data[loc].child=child;
287

	
288
          // left_neighb set for p_loc
289
          if( _data[loc].child!=p_loc ) {
290
            while( _data[child].right_neighbor!=loc )
291
              child=_data[child].right_neighbor;
292
            _data[child].right_neighbor=p_loc;
293
          }
294

	
295
          // left_neighb set for loc
296
          parent=_data[p_loc].parent;
297
          if( -1!=parent ) child=_data[parent].child;
298
          else child=_head;
299

	
300
          if( child!=p_loc ) {
301
            while( _data[child].right_neighbor!=p_loc )
302
              child=_data[child].right_neighbor;
303
            _data[child].right_neighbor=loc;
304
          }
305

	
306
          neighb=_data[p_loc].right_neighbor;
307
          _data[p_loc].right_neighbor=_data[loc].right_neighbor;
308
          _data[loc].right_neighbor=neighb;
309

	
310
          _data[p_loc].parent=loc;
311
          _data[loc].parent=parent;
312

	
313
          if( -1!=parent && _data[parent].child==p_loc )
314
            _data[parent].child=loc;
315

	
316
          /*if new parent will be the first root*/
317
          if( _head==p_loc )
318
            _head=loc;
319

	
320
          p_loc=_data[loc].parent;
321
        }
259
      int p=_data[i].parent;
260
      _data[i].prio=value;
261
      
262
      while( p!=-1 && _comp(value, _data[p].prio) ) {
263
        _data[i].name=_data[p].name;
264
        _data[i].prio=_data[p].prio;
265
        _data[p].name=item;
266
        _data[p].prio=value;
267
        _iim[_data[i].name]=i;
268
        i=p;
269
        p=_data[p].parent;
322 270
      }
323
      if( _comp(value,_data[_min].prio) ) {
324
        _min=i;
325
      }
271
      _iim[item]=i;
272
      if ( _comp(value, _data[_min].prio) ) _min=i;
326 273
    }
327 274

	
328 275
    /// \brief Increase the priority of an item to the given value.
329 276
    ///
330 277
    /// This function increases the priority of an item to the given value.
331 278
    /// \param item The item.
332 279
    /// \param value The priority.
333 280
    /// \pre \e item must be stored in the heap with priority at most \e value.
334 281
    void increase (Item item, const Prio& value) {
335 282
      erase(item);
336 283
      push(item, value);
337 284
    }
338 285

	
339 286
    /// \brief Return the state of an item.
340 287
    ///
341 288
    /// This method returns \c PRE_HEAP if the given item has never
342 289
    /// been in the heap, \c IN_HEAP if it is in the heap at the moment,
343 290
    /// and \c POST_HEAP otherwise.
344 291
    /// In the latter case it is possible that the item will get back
345 292
    /// to the heap again.
346 293
    /// \param item The item.
347 294
    State state(const Item &item) const {
348 295
      int i=_iim[item];
349 296
      if( i>=0 ) {
... ...
@@ -354,161 +301,145 @@
354 301
    }
355 302

	
356 303
    /// \brief Set the state of an item in the heap.
357 304
    ///
358 305
    /// This function sets the state of the given item in the heap.
359 306
    /// It can be used to manually clear the heap when it is important
360 307
    /// to achive better time complexity.
361 308
    /// \param i The item.
362 309
    /// \param st The state. It should not be \c IN_HEAP.
363 310
    void state(const Item& i, State st) {
364 311
      switch (st) {
365 312
      case POST_HEAP:
366 313
      case PRE_HEAP:
367 314
        if (state(i) == IN_HEAP) {
368 315
          erase(i);
369 316
        }
370 317
        _iim[i] = st;
371 318
        break;
372 319
      case IN_HEAP:
373 320
        break;
374 321
      }
375 322
    }
376 323

	
377 324
  private:
325
    
326
    // Find the minimum of the roots
378 327
    int findMin() {
379
      int min_loc=-1, min_val;
380
      int x=_head;
381
      if( x!=-1 ) {
382
        min_val=_data[x].prio;
383
        min_loc=x;
384
        x=_data[x].right_neighbor;
385

	
386
        while( x!=-1 ) {
328
      if( _head!=-1 ) {
329
        int min_loc=_head, min_val=_data[_head].prio;
330
        for( int x=_data[_head].right_neighbor; x!=-1;
331
             x=_data[x].right_neighbor ) {
387 332
          if( _comp( _data[x].prio,min_val ) ) {
388 333
            min_val=_data[x].prio;
389 334
            min_loc=x;
390 335
          }
391
          x=_data[x].right_neighbor;
392 336
        }
337
        return min_loc;
393 338
      }
394
      return min_loc;
339
      else return -1;
395 340
    }
396 341

	
342
    // Merge the heap with another heap starting at the given position
397 343
    void merge(int a) {
398
      interleave(a);
399

	
344
      if( _head==-1 || a==-1 ) return;
345
      if( _data[a].right_neighbor==-1 &&
346
          _data[a].degree<=_data[_head].degree ) {
347
        _data[a].right_neighbor=_head;
348
        _head=a;
349
      } else {
350
        interleave(a);
351
      }
352
      if( _data[_head].right_neighbor==-1 ) return;
353
      
400 354
      int x=_head;
401
      if( -1!=x ) {
402
        int x_prev=-1, x_next=_data[x].right_neighbor;
403
        while( -1!=x_next ) {
404
          if( _data[x].degree!=_data[x_next].degree || ( -1!=_data[x_next].right_neighbor && _data[_data[x_next].right_neighbor].degree==_data[x].degree ) ) {
405
            x_prev=x;
355
      int x_prev=-1, x_next=_data[x].right_neighbor;
356
      while( x_next!=-1 ) {
357
        if( _data[x].degree!=_data[x_next].degree ||
358
            ( _data[x_next].right_neighbor!=-1 &&
359
              _data[_data[x_next].right_neighbor].degree==_data[x].degree ) ) {
360
          x_prev=x;
361
          x=x_next;
362
        }
363
        else {
364
          if( _comp(_data[x_next].prio,_data[x].prio) ) {
365
            if( x_prev==-1 ) {
366
              _head=x_next;
367
            } else {
368
              _data[x_prev].right_neighbor=x_next;
369
            }
370
            fuse(x,x_next);
406 371
            x=x_next;
407 372
          }
408 373
          else {
409
            if( _comp(_data[x].prio,_data[x_next].prio) ) {
410
              _data[x].right_neighbor=_data[x_next].right_neighbor;
411
              fuse(x_next,x);
412
            }
413
            else {
414
              if( -1==x_prev ) { _head=x_next; }
415
              else {
416
                _data[x_prev].right_neighbor=x_next;
417
              }
418
              fuse(x,x_next);
419
              x=x_next;
420
            }
374
            _data[x].right_neighbor=_data[x_next].right_neighbor;
375
            fuse(x_next,x);
421 376
          }
422
          x_next=_data[x].right_neighbor;
423 377
        }
378
        x_next=_data[x].right_neighbor;
424 379
      }
425 380
    }
426 381

	
382
    // Interleave the elements of the given list into the list of the roots
427 383
    void interleave(int a) {
428
      int other=-1, head_other=-1;
429

	
430
      while( -1!=a || -1!=_head ) {
431
        if( -1==a ) {
432
          if( -1==head_other ) {
433
            head_other=_head;
434
          }
435
          else {
436
            _data[other].right_neighbor=_head;
437
          }
438
          _head=-1;
439
        }
440
        else if( -1==_head ) {
441
          if( -1==head_other ) {
442
            head_other=a;
443
          }
444
          else {
445
            _data[other].right_neighbor=a;
446
          }
447
          a=-1;
384
      int p=_head, q=a;
385
      int curr=_data.size();
386
      _data.push_back(Store());
387
      
388
      while( p!=-1 || q!=-1 ) {
389
        if( q==-1 || ( p!=-1 && _data[p].degree<_data[q].degree ) ) {
390
          _data[curr].right_neighbor=p;
391
          curr=p;
392
          p=_data[p].right_neighbor;
448 393
        }
449 394
        else {
450
          if( _data[a].degree<_data[_head].degree ) {
451
            if( -1==head_other ) {
452
              head_other=a;
453
            }
454
            else {
455
              _data[other].right_neighbor=a;
456
            }
457
            other=a;
458
            a=_data[a].right_neighbor;
459
          }
460
          else {
461
            if( -1==head_other ) {
462
              head_other=_head;
463
            }
464
            else {
465
              _data[other].right_neighbor=_head;
466
            }
467
            other=_head;
468
            _head=_data[_head].right_neighbor;
469
          }
395
          _data[curr].right_neighbor=q;
396
          curr=q;
397
          q=_data[q].right_neighbor;
470 398
        }
471 399
      }
472
      _head=head_other;
400
      
401
      _head=_data.back().right_neighbor;
402
      _data.pop_back();
473 403
    }
474 404

	
475
    // Lacing a under b
405
    // Lace node a under node b
476 406
    void fuse(int a, int b) {
477 407
      _data[a].parent=b;
478 408
      _data[a].right_neighbor=_data[b].child;
479 409
      _data[b].child=a;
480 410

	
481 411
      ++_data[b].degree;
482 412
    }
483 413

	
484
    // It is invoked only if a has siblings.
414
    // Unlace node a (if it has siblings)
485 415
    void unlace(int a) {
486 416
      int neighb=_data[a].right_neighbor;
487 417
      int other=_head;
488 418

	
489 419
      while( _data[other].right_neighbor!=a )
490 420
        other=_data[other].right_neighbor;
491 421
      _data[other].right_neighbor=neighb;
492 422
    }
493 423

	
494 424
  private:
495 425

	
496
    class store {
426
    class Store {
497 427
      friend class BinomHeap;
498 428

	
499 429
      Item name;
500 430
      int parent;
501 431
      int right_neighbor;
502 432
      int child;
503 433
      int degree;
504 434
      bool in;
505 435
      Prio prio;
506 436

	
507
      store() : parent(-1), right_neighbor(-1), child(-1), degree(0), in(true) {}
437
      Store() : parent(-1), right_neighbor(-1), child(-1), degree(0),
438
        in(true) {}
508 439
    };
509 440
  };
510 441

	
511 442
} //namespace lemon
512 443

	
513 444
#endif //LEMON_BINOM_HEAP_H
514 445

	
0 comments (0 inline)