Home | History | Annotate | Download | only in bits
      1 // Heap implementation -*- C++ -*-
      2 
      3 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
      4 // Free Software Foundation, Inc.
      5 //
      6 // This file is part of the GNU ISO C++ Library.  This library is free
      7 // software; you can redistribute it and/or modify it under the
      8 // terms of the GNU General Public License as published by the
      9 // Free Software Foundation; either version 3, or (at your option)
     10 // any later version.
     11 
     12 // This library is distributed in the hope that it will be useful,
     13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 // GNU General Public License for more details.
     16 
     17 // Under Section 7 of GPL version 3, you are granted additional
     18 // permissions described in the GCC Runtime Library Exception, version
     19 // 3.1, as published by the Free Software Foundation.
     20 
     21 // You should have received a copy of the GNU General Public License and
     22 // a copy of the GCC Runtime Library Exception along with this program;
     23 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24 // <http://www.gnu.org/licenses/>.
     25 
     26 /*
     27  *
     28  * Copyright (c) 1994
     29  * Hewlett-Packard Company
     30  *
     31  * Permission to use, copy, modify, distribute and sell this software
     32  * and its documentation for any purpose is hereby granted without fee,
     33  * provided that the above copyright notice appear in all copies and
     34  * that both that copyright notice and this permission notice appear
     35  * in supporting documentation.  Hewlett-Packard Company makes no
     36  * representations about the suitability of this software for any
     37  * purpose.  It is provided "as is" without express or implied warranty.
     38  *
     39  * Copyright (c) 1997
     40  * Silicon Graphics Computer Systems, Inc.
     41  *
     42  * Permission to use, copy, modify, distribute and sell this software
     43  * and its documentation for any purpose is hereby granted without fee,
     44  * provided that the above copyright notice appear in all copies and
     45  * that both that copyright notice and this permission notice appear
     46  * in supporting documentation.  Silicon Graphics makes no
     47  * representations about the suitability of this software for any
     48  * purpose.  It is provided "as is" without express or implied warranty.
     49  */
     50 
     51 /** @file stl_heap.h
     52  *  This is an internal header file, included by other library headers.
     53  *  You should not attempt to use it directly.
     54  */
     55 
     56 #ifndef _STL_HEAP_H
     57 #define _STL_HEAP_H 1
     58 
     59 #include <debug/debug.h>
     60 #include <bits/move.h>
     61 
     62 _GLIBCXX_BEGIN_NAMESPACE(std)
     63 
     64   /**
     65    * @defgroup heap_algorithms Heap Algorithms
     66    * @ingroup sorting_algorithms
     67    */
     68 
     69   template<typename _RandomAccessIterator, typename _Distance>
     70     _Distance
     71     __is_heap_until(_RandomAccessIterator __first, _Distance __n)
     72     {
     73       _Distance __parent = 0;
     74       for (_Distance __child = 1; __child < __n; ++__child)
     75 	{
     76 	  if (__first[__parent] < __first[__child])
     77 	    return __child;
     78 	  if ((__child & 1) == 0)
     79 	    ++__parent;
     80 	}
     81       return __n;
     82     }
     83 
     84   template<typename _RandomAccessIterator, typename _Distance,
     85 	   typename _Compare>
     86     _Distance
     87     __is_heap_until(_RandomAccessIterator __first, _Distance __n,
     88 		    _Compare __comp)
     89     {
     90       _Distance __parent = 0;
     91       for (_Distance __child = 1; __child < __n; ++__child)
     92 	{
     93 	  if (__comp(__first[__parent], __first[__child]))
     94 	    return __child;
     95 	  if ((__child & 1) == 0)
     96 	    ++__parent;
     97 	}
     98       return __n;
     99     }
    100 
    101   // __is_heap, a predicate testing whether or not a range is a heap.
    102   // This function is an extension, not part of the C++ standard.
    103   template<typename _RandomAccessIterator, typename _Distance>
    104     inline bool
    105     __is_heap(_RandomAccessIterator __first, _Distance __n)
    106     { return std::__is_heap_until(__first, __n) == __n; }
    107 
    108   template<typename _RandomAccessIterator, typename _Compare,
    109 	   typename _Distance>
    110     inline bool
    111     __is_heap(_RandomAccessIterator __first, _Compare __comp, _Distance __n)
    112     { return std::__is_heap_until(__first, __n, __comp) == __n; }
    113 
    114   template<typename _RandomAccessIterator>
    115     inline bool
    116     __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
    117     { return std::__is_heap(__first, std::distance(__first, __last)); }
    118 
    119   template<typename _RandomAccessIterator, typename _Compare>
    120     inline bool
    121     __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
    122 	      _Compare __comp)
    123     { return std::__is_heap(__first, __comp, std::distance(__first, __last)); }
    124 
    125   // Heap-manipulation functions: push_heap, pop_heap, make_heap, sort_heap,
    126   // + is_heap and is_heap_until in C++0x.
    127 
    128   template<typename _RandomAccessIterator, typename _Distance, typename _Tp>
    129     void
    130     __push_heap(_RandomAccessIterator __first,
    131 		_Distance __holeIndex, _Distance __topIndex, _Tp __value)
    132     {
    133       _Distance __parent = (__holeIndex - 1) / 2;
    134       while (__holeIndex > __topIndex && *(__first + __parent) < __value)
    135 	{
    136 	  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
    137 	  __holeIndex = __parent;
    138 	  __parent = (__holeIndex - 1) / 2;
    139 	}
    140       *(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
    141     }
    142 
    143   /**
    144    *  @brief  Push an element onto a heap.
    145    *  @param  first  Start of heap.
    146    *  @param  last   End of heap + element.
    147    *  @ingroup heap_algorithms
    148    *
    149    *  This operation pushes the element at last-1 onto the valid heap over the
    150    *  range [first,last-1).  After completion, [first,last) is a valid heap.
    151   */
    152   template<typename _RandomAccessIterator>
    153     inline void
    154     push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
    155     {
    156       typedef typename iterator_traits<_RandomAccessIterator>::value_type
    157 	  _ValueType;
    158       typedef typename iterator_traits<_RandomAccessIterator>::difference_type
    159 	  _DistanceType;
    160 
    161       // concept requirements
    162       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
    163 	    _RandomAccessIterator>)
    164       __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
    165       __glibcxx_requires_valid_range(__first, __last);
    166       __glibcxx_requires_heap(__first, __last - 1);
    167 
    168       _ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
    169       std::__push_heap(__first, _DistanceType((__last - __first) - 1),
    170 		       _DistanceType(0), _GLIBCXX_MOVE(__value));
    171     }
    172 
    173   template<typename _RandomAccessIterator, typename _Distance, typename _Tp,
    174 	   typename _Compare>
    175     void
    176     __push_heap(_RandomAccessIterator __first, _Distance __holeIndex,
    177 		_Distance __topIndex, _Tp __value, _Compare __comp)
    178     {
    179       _Distance __parent = (__holeIndex - 1) / 2;
    180       while (__holeIndex > __topIndex
    181 	     && __comp(*(__first + __parent), __value))
    182 	{
    183 	  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
    184 	  __holeIndex = __parent;
    185 	  __parent = (__holeIndex - 1) / 2;
    186 	}
    187       *(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
    188     }
    189 
    190   /**
    191    *  @brief  Push an element onto a heap using comparison functor.
    192    *  @param  first  Start of heap.
    193    *  @param  last   End of heap + element.
    194    *  @param  comp   Comparison functor.
    195    *  @ingroup heap_algorithms
    196    *
    197    *  This operation pushes the element at last-1 onto the valid heap over the
    198    *  range [first,last-1).  After completion, [first,last) is a valid heap.
    199    *  Compare operations are performed using comp.
    200   */
    201   template<typename _RandomAccessIterator, typename _Compare>
    202     inline void
    203     push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
    204 	      _Compare __comp)
    205     {
    206       typedef typename iterator_traits<_RandomAccessIterator>::value_type
    207 	  _ValueType;
    208       typedef typename iterator_traits<_RandomAccessIterator>::difference_type
    209 	  _DistanceType;
    210 
    211       // concept requirements
    212       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
    213 	    _RandomAccessIterator>)
    214       __glibcxx_requires_valid_range(__first, __last);
    215       __glibcxx_requires_heap_pred(__first, __last - 1, __comp);
    216 
    217       _ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
    218       std::__push_heap(__first, _DistanceType((__last - __first) - 1),
    219 		       _DistanceType(0), _GLIBCXX_MOVE(__value), __comp);
    220     }
    221 
    222   template<typename _RandomAccessIterator, typename _Distance, typename _Tp>
    223     void
    224     __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
    225 		  _Distance __len, _Tp __value)
    226     {
    227       const _Distance __topIndex = __holeIndex;
    228       _Distance __secondChild = __holeIndex;
    229       while (__secondChild < (__len - 1) / 2)
    230 	{
    231 	  __secondChild = 2 * (__secondChild + 1);
    232 	  if (*(__first + __secondChild) < *(__first + (__secondChild - 1)))
    233 	    __secondChild--;
    234 	  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
    235 	  __holeIndex = __secondChild;
    236 	}
    237       if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
    238 	{
    239 	  __secondChild = 2 * (__secondChild + 1);
    240 	  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first
    241 						     + (__secondChild - 1)));
    242 	  __holeIndex = __secondChild - 1;
    243 	}
    244       std::__push_heap(__first, __holeIndex, __topIndex,
    245 		       _GLIBCXX_MOVE(__value));
    246     }
    247 
    248   template<typename _RandomAccessIterator>
    249     inline void
    250     __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
    251 	       _RandomAccessIterator __result)
    252     {
    253       typedef typename iterator_traits<_RandomAccessIterator>::value_type
    254 	_ValueType;
    255       typedef typename iterator_traits<_RandomAccessIterator>::difference_type
    256 	_DistanceType;
    257 
    258       _ValueType __value = _GLIBCXX_MOVE(*__result);
    259       *__result = _GLIBCXX_MOVE(*__first);
    260       std::__adjust_heap(__first, _DistanceType(0),
    261 			 _DistanceType(__last - __first),
    262 			 _GLIBCXX_MOVE(__value));
    263     }
    264 
    265   /**
    266    *  @brief  Pop an element off a heap.
    267    *  @param  first  Start of heap.
    268    *  @param  last   End of heap.
    269    *  @ingroup heap_algorithms
    270    *
    271    *  This operation pops the top of the heap.  The elements first and last-1
    272    *  are swapped and [first,last-1) is made into a heap.
    273   */
    274   template<typename _RandomAccessIterator>
    275     inline void
    276     pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
    277     {
    278       typedef typename iterator_traits<_RandomAccessIterator>::value_type
    279 	_ValueType;
    280 
    281       // concept requirements
    282       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
    283 	    _RandomAccessIterator>)
    284       __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
    285       __glibcxx_requires_valid_range(__first, __last);
    286       __glibcxx_requires_heap(__first, __last);
    287 
    288       --__last;
    289       std::__pop_heap(__first, __last, __last);
    290     }
    291 
    292   template<typename _RandomAccessIterator, typename _Distance,
    293 	   typename _Tp, typename _Compare>
    294     void
    295     __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
    296 		  _Distance __len, _Tp __value, _Compare __comp)
    297     {
    298       const _Distance __topIndex = __holeIndex;
    299       _Distance __secondChild = __holeIndex;
    300       while (__secondChild < (__len - 1) / 2)
    301 	{
    302 	  __secondChild = 2 * (__secondChild + 1);
    303 	  if (__comp(*(__first + __secondChild),
    304 		     *(__first + (__secondChild - 1))))
    305 	    __secondChild--;
    306 	  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
    307 	  __holeIndex = __secondChild;
    308 	}
    309       if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
    310 	{
    311 	  __secondChild = 2 * (__secondChild + 1);
    312 	  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first
    313 						     + (__secondChild - 1)));
    314 	  __holeIndex = __secondChild - 1;
    315 	}
    316       std::__push_heap(__first, __holeIndex, __topIndex,
    317 		       _GLIBCXX_MOVE(__value), __comp);
    318     }
    319 
    320   template<typename _RandomAccessIterator, typename _Compare>
    321     inline void
    322     __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
    323 	       _RandomAccessIterator __result, _Compare __comp)
    324     {
    325       typedef typename iterator_traits<_RandomAccessIterator>::value_type
    326 	_ValueType;
    327       typedef typename iterator_traits<_RandomAccessIterator>::difference_type
    328 	_DistanceType;
    329 
    330       _ValueType __value = _GLIBCXX_MOVE(*__result);
    331       *__result = _GLIBCXX_MOVE(*__first);
    332       std::__adjust_heap(__first, _DistanceType(0),
    333 			 _DistanceType(__last - __first),
    334 			 _GLIBCXX_MOVE(__value), __comp);
    335     }
    336 
    337   /**
    338    *  @brief  Pop an element off a heap using comparison functor.
    339    *  @param  first  Start of heap.
    340    *  @param  last   End of heap.
    341    *  @param  comp   Comparison functor to use.
    342    *  @ingroup heap_algorithms
    343    *
    344    *  This operation pops the top of the heap.  The elements first and last-1
    345    *  are swapped and [first,last-1) is made into a heap.  Comparisons are
    346    *  made using comp.
    347   */
    348   template<typename _RandomAccessIterator, typename _Compare>
    349     inline void
    350     pop_heap(_RandomAccessIterator __first,
    351 	     _RandomAccessIterator __last, _Compare __comp)
    352     {
    353       // concept requirements
    354       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
    355 	    _RandomAccessIterator>)
    356       __glibcxx_requires_valid_range(__first, __last);
    357       __glibcxx_requires_heap_pred(__first, __last, __comp);
    358 
    359       --__last;
    360       std::__pop_heap(__first, __last, __last, __comp);
    361     }
    362 
    363   /**
    364    *  @brief  Construct a heap over a range.
    365    *  @param  first  Start of heap.
    366    *  @param  last   End of heap.
    367    *  @ingroup heap_algorithms
    368    *
    369    *  This operation makes the elements in [first,last) into a heap.
    370   */
    371   template<typename _RandomAccessIterator>
    372     void
    373     make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
    374     {
    375       typedef typename iterator_traits<_RandomAccessIterator>::value_type
    376 	  _ValueType;
    377       typedef typename iterator_traits<_RandomAccessIterator>::difference_type
    378 	  _DistanceType;
    379 
    380       // concept requirements
    381       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
    382 	    _RandomAccessIterator>)
    383       __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
    384       __glibcxx_requires_valid_range(__first, __last);
    385 
    386       if (__last - __first < 2)
    387 	return;
    388 
    389       const _DistanceType __len = __last - __first;
    390       _DistanceType __parent = (__len - 2) / 2;
    391       while (true)
    392 	{
    393 	  _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
    394 	  std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value));
    395 	  if (__parent == 0)
    396 	    return;
    397 	  __parent--;
    398 	}
    399     }
    400 
    401   /**
    402    *  @brief  Construct a heap over a range using comparison functor.
    403    *  @param  first  Start of heap.
    404    *  @param  last   End of heap.
    405    *  @param  comp   Comparison functor to use.
    406    *  @ingroup heap_algorithms
    407    *
    408    *  This operation makes the elements in [first,last) into a heap.
    409    *  Comparisons are made using comp.
    410   */
    411   template<typename _RandomAccessIterator, typename _Compare>
    412     void
    413     make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
    414 	      _Compare __comp)
    415     {
    416       typedef typename iterator_traits<_RandomAccessIterator>::value_type
    417 	  _ValueType;
    418       typedef typename iterator_traits<_RandomAccessIterator>::difference_type
    419 	  _DistanceType;
    420 
    421       // concept requirements
    422       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
    423 	    _RandomAccessIterator>)
    424       __glibcxx_requires_valid_range(__first, __last);
    425 
    426       if (__last - __first < 2)
    427 	return;
    428 
    429       const _DistanceType __len = __last - __first;
    430       _DistanceType __parent = (__len - 2) / 2;
    431       while (true)
    432 	{
    433 	  _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
    434 	  std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value),
    435 			     __comp);
    436 	  if (__parent == 0)
    437 	    return;
    438 	  __parent--;
    439 	}
    440     }
    441 
    442   /**
    443    *  @brief  Sort a heap.
    444    *  @param  first  Start of heap.
    445    *  @param  last   End of heap.
    446    *  @ingroup heap_algorithms
    447    *
    448    *  This operation sorts the valid heap in the range [first,last).
    449   */
    450   template<typename _RandomAccessIterator>
    451     void
    452     sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
    453     {
    454       // concept requirements
    455       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
    456 	    _RandomAccessIterator>)
    457       __glibcxx_function_requires(_LessThanComparableConcept<
    458 	    typename iterator_traits<_RandomAccessIterator>::value_type>)
    459       __glibcxx_requires_valid_range(__first, __last);
    460       __glibcxx_requires_heap(__first, __last);
    461 
    462       while (__last - __first > 1)
    463 	{
    464 	  --__last;
    465 	  std::__pop_heap(__first, __last, __last);
    466 	}
    467     }
    468 
    469   /**
    470    *  @brief  Sort a heap using comparison functor.
    471    *  @param  first  Start of heap.
    472    *  @param  last   End of heap.
    473    *  @param  comp   Comparison functor to use.
    474    *  @ingroup heap_algorithms
    475    *
    476    *  This operation sorts the valid heap in the range [first,last).
    477    *  Comparisons are made using comp.
    478   */
    479   template<typename _RandomAccessIterator, typename _Compare>
    480     void
    481     sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
    482 	      _Compare __comp)
    483     {
    484       // concept requirements
    485       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
    486 	    _RandomAccessIterator>)
    487       __glibcxx_requires_valid_range(__first, __last);
    488       __glibcxx_requires_heap_pred(__first, __last, __comp);
    489 
    490       while (__last - __first > 1)
    491 	{
    492 	  --__last;
    493 	  std::__pop_heap(__first, __last, __last, __comp);
    494 	}
    495     }
    496 
    497 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    498   /**
    499    *  @brief  Search the end of a heap.
    500    *  @param  first  Start of range.
    501    *  @param  last   End of range.
    502    *  @return  An iterator pointing to the first element not in the heap.
    503    *  @ingroup heap_algorithms
    504    *
    505    *  This operation returns the last iterator i in [first, last) for which
    506    *  the range [first, i) is a heap.
    507   */
    508   template<typename _RandomAccessIterator>
    509     inline _RandomAccessIterator
    510     is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last)
    511     {
    512       // concept requirements
    513       __glibcxx_function_requires(_RandomAccessIteratorConcept<
    514 	    _RandomAccessIterator>)
    515       __glibcxx_function_requires(_LessThanComparableConcept<
    516 	    typename iterator_traits<_RandomAccessIterator>::value_type>)
    517       __glibcxx_requires_valid_range(__first, __last);
    518 
    519       return __first + std::__is_heap_until(__first, std::distance(__first,
    520 								   __last));
    521     }
    522 
    523   /**
    524    *  @brief  Search the end of a heap using comparison functor.
    525    *  @param  first  Start of range.
    526    *  @param  last   End of range.
    527    *  @param  comp   Comparison functor to use.
    528    *  @return  An iterator pointing to the first element not in the heap.
    529    *  @ingroup heap_algorithms
    530    *
    531    *  This operation returns the last iterator i in [first, last) for which
    532    *  the range [first, i) is a heap.  Comparisons are made using comp.
    533   */
    534   template<typename _RandomAccessIterator, typename _Compare>
    535     inline _RandomAccessIterator
    536     is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last,
    537 		  _Compare __comp)
    538     {
    539       // concept requirements
    540       __glibcxx_function_requires(_RandomAccessIteratorConcept<
    541 	    _RandomAccessIterator>)
    542       __glibcxx_requires_valid_range(__first, __last);
    543 
    544       return __first + std::__is_heap_until(__first, std::distance(__first,
    545 								   __last),
    546 					    __comp);
    547     }
    548 
    549   /**
    550    *  @brief  Determines whether a range is a heap.
    551    *  @param  first  Start of range.
    552    *  @param  last   End of range.
    553    *  @return  True if range is a heap, false otherwise.
    554    *  @ingroup heap_algorithms
    555   */
    556   template<typename _RandomAccessIterator>
    557     inline bool
    558     is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
    559     { return std::is_heap_until(__first, __last) == __last; }
    560 
    561   /**
    562    *  @brief  Determines whether a range is a heap using comparison functor.
    563    *  @param  first  Start of range.
    564    *  @param  last   End of range.
    565    *  @param  comp   Comparison functor to use.
    566    *  @return  True if range is a heap, false otherwise.
    567    *  @ingroup heap_algorithms
    568   */
    569   template<typename _RandomAccessIterator, typename _Compare>
    570     inline bool
    571     is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
    572 	    _Compare __comp)
    573     { return std::is_heap_until(__first, __last, __comp) == __last; }
    574 #endif
    575 
    576 _GLIBCXX_END_NAMESPACE
    577 
    578 #endif /* _STL_HEAP_H */
    579