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