1 // Heap implementation -*- C++ -*-
2 
3 // Copyright (C) 2001-2016 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 
_GLIBCXX_VISIBILITY(default)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_irreflexive(__first, __last);
163       __glibcxx_requires_heap(__first, __last - 1);
164 
165       _ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
166       std::__push_heap(__first, _DistanceType((__last - __first) - 1),
167 		       _DistanceType(0), _GLIBCXX_MOVE(__value),
168 		       __gnu_cxx::__ops::__iter_less_val());
169     }
170 
171   /**
172    *  @brief  Push an element onto a heap using comparison functor.
173    *  @param  __first  Start of heap.
174    *  @param  __last   End of heap + element.
175    *  @param  __comp   Comparison functor.
176    *  @ingroup heap_algorithms
177    *
178    *  This operation pushes the element at __last-1 onto the valid
179    *  heap over the range [__first,__last-1).  After completion,
180    *  [__first,__last) is a valid heap.  Compare operations are
181    *  performed using comp.
182   */
183   template<typename _RandomAccessIterator, typename _Compare>
184     inline void
185     push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
186 	      _Compare __comp)
187     {
188       typedef typename iterator_traits<_RandomAccessIterator>::value_type
189 	  _ValueType;
190       typedef typename iterator_traits<_RandomAccessIterator>::difference_type
191 	  _DistanceType;
192 
193       // concept requirements
194       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
195 	    _RandomAccessIterator>)
196       __glibcxx_requires_valid_range(__first, __last);
197       __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
198       __glibcxx_requires_heap_pred(__first, __last - 1, __comp);
199 
200       _ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
201       std::__push_heap(__first, _DistanceType((__last - __first) - 1),
202 		       _DistanceType(0), _GLIBCXX_MOVE(__value),
203 		       __gnu_cxx::__ops::__iter_comp_val(__comp));
204     }
205 
206   template<typename _RandomAccessIterator, typename _Distance,
207 	   typename _Tp, typename _Compare>
208     void
209     __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
210 		  _Distance __len, _Tp __value, _Compare __comp)
211     {
212       const _Distance __topIndex = __holeIndex;
213       _Distance __secondChild = __holeIndex;
214       while (__secondChild < (__len - 1) / 2)
215 	{
216 	  __secondChild = 2 * (__secondChild + 1);
217 	  if (__comp(__first + __secondChild,
218 		     __first + (__secondChild - 1)))
219 	    __secondChild--;
220 	  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
221 	  __holeIndex = __secondChild;
222 	}
223       if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
224 	{
225 	  __secondChild = 2 * (__secondChild + 1);
226 	  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first
227 						     + (__secondChild - 1)));
228 	  __holeIndex = __secondChild - 1;
229 	}
230       std::__push_heap(__first, __holeIndex, __topIndex,
231 		       _GLIBCXX_MOVE(__value),
232 		       __gnu_cxx::__ops::__iter_comp_val(__comp));
233     }
234 
235   template<typename _RandomAccessIterator, typename _Compare>
236     inline void
237     __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
238 	       _RandomAccessIterator __result, _Compare __comp)
239     {
240       typedef typename iterator_traits<_RandomAccessIterator>::value_type
241 	_ValueType;
242       typedef typename iterator_traits<_RandomAccessIterator>::difference_type
243 	_DistanceType;
244 
245       _ValueType __value = _GLIBCXX_MOVE(*__result);
246       *__result = _GLIBCXX_MOVE(*__first);
247       std::__adjust_heap(__first, _DistanceType(0),
248 			 _DistanceType(__last - __first),
249 			 _GLIBCXX_MOVE(__value), __comp);
250     }
251 
252   /**
253    *  @brief  Pop an element off a heap.
254    *  @param  __first  Start of heap.
255    *  @param  __last   End of heap.
256    *  @pre    [__first, __last) is a valid, non-empty range.
257    *  @ingroup heap_algorithms
258    *
259    *  This operation pops the top of the heap.  The elements __first
260    *  and __last-1 are swapped and [__first,__last-1) is made into a
261    *  heap.
262   */
263   template<typename _RandomAccessIterator>
264     inline void
265     pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
266     {
267       // concept requirements
268       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
269 	    _RandomAccessIterator>)
270       __glibcxx_function_requires(_LessThanComparableConcept<
271 	typename iterator_traits<_RandomAccessIterator>::value_type>)
272       __glibcxx_requires_non_empty_range(__first, __last);
273       __glibcxx_requires_valid_range(__first, __last);
274       __glibcxx_requires_irreflexive(__first, __last);
275       __glibcxx_requires_heap(__first, __last);
276 
277       if (__last - __first > 1)
278 	{
279 	  --__last;
280 	  std::__pop_heap(__first, __last, __last,
281 			  __gnu_cxx::__ops::__iter_less_iter());
282 	}
283     }
284 
285   /**
286    *  @brief  Pop an element off a heap using comparison functor.
287    *  @param  __first  Start of heap.
288    *  @param  __last   End of heap.
289    *  @param  __comp   Comparison functor to use.
290    *  @ingroup heap_algorithms
291    *
292    *  This operation pops the top of the heap.  The elements __first
293    *  and __last-1 are swapped and [__first,__last-1) is made into a
294    *  heap.  Comparisons are made using comp.
295   */
296   template<typename _RandomAccessIterator, typename _Compare>
297     inline void
298     pop_heap(_RandomAccessIterator __first,
299 	     _RandomAccessIterator __last, _Compare __comp)
300     {
301       // concept requirements
302       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
303 	    _RandomAccessIterator>)
304       __glibcxx_requires_valid_range(__first, __last);
305       __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
306       __glibcxx_requires_non_empty_range(__first, __last);
307       __glibcxx_requires_heap_pred(__first, __last, __comp);
308 
309       if (__last - __first > 1)
310 	{
311 	  --__last;
312 	  std::__pop_heap(__first, __last, __last,
313 			  __gnu_cxx::__ops::__iter_comp_iter(__comp));
314 	}
315     }
316 
317   template<typename _RandomAccessIterator, typename _Compare>
318     void
319     __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
320 		_Compare __comp)
321     {
322       typedef typename iterator_traits<_RandomAccessIterator>::value_type
323 	  _ValueType;
324       typedef typename iterator_traits<_RandomAccessIterator>::difference_type
325 	  _DistanceType;
326 
327       if (__last - __first < 2)
328 	return;
329 
330       const _DistanceType __len = __last - __first;
331       _DistanceType __parent = (__len - 2) / 2;
332       while (true)
333 	{
334 	  _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
335 	  std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value),
336 			     __comp);
337 	  if (__parent == 0)
338 	    return;
339 	  __parent--;
340 	}
341     }
342 
343   /**
344    *  @brief  Construct a heap over a range.
345    *  @param  __first  Start of heap.
346    *  @param  __last   End of heap.
347    *  @ingroup heap_algorithms
348    *
349    *  This operation makes the elements in [__first,__last) into a heap.
350   */
351   template<typename _RandomAccessIterator>
352     inline void
353     make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
354     {
355       // concept requirements
356       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
357 	    _RandomAccessIterator>)
358       __glibcxx_function_requires(_LessThanComparableConcept<
359 	    typename iterator_traits<_RandomAccessIterator>::value_type>)
360       __glibcxx_requires_valid_range(__first, __last);
361       __glibcxx_requires_irreflexive(__first, __last);
362 
363       std::__make_heap(__first, __last,
364 		       __gnu_cxx::__ops::__iter_less_iter());
365     }
366 
367   /**
368    *  @brief  Construct a heap over a range using comparison functor.
369    *  @param  __first  Start of heap.
370    *  @param  __last   End of heap.
371    *  @param  __comp   Comparison functor to use.
372    *  @ingroup heap_algorithms
373    *
374    *  This operation makes the elements in [__first,__last) into a heap.
375    *  Comparisons are made using __comp.
376   */
377   template<typename _RandomAccessIterator, typename _Compare>
378     inline void
379     make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
380 	      _Compare __comp)
381     {
382       // concept requirements
383       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
384 	    _RandomAccessIterator>)
385       __glibcxx_requires_valid_range(__first, __last);
386       __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
387 
388       std::__make_heap(__first, __last,
389 		       __gnu_cxx::__ops::__iter_comp_iter(__comp));
390     }
391 
392   template<typename _RandomAccessIterator, typename _Compare>
393     void
394     __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
395 		_Compare __comp)
396     {
397       while (__last - __first > 1)
398 	{
399 	  --__last;
400 	  std::__pop_heap(__first, __last, __last, __comp);
401 	}
402     }
403 
404   /**
405    *  @brief  Sort a heap.
406    *  @param  __first  Start of heap.
407    *  @param  __last   End of heap.
408    *  @ingroup heap_algorithms
409    *
410    *  This operation sorts the valid heap in the range [__first,__last).
411   */
412   template<typename _RandomAccessIterator>
413     inline void
414     sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
415     {
416       // concept requirements
417       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
418 	    _RandomAccessIterator>)
419       __glibcxx_function_requires(_LessThanComparableConcept<
420 	    typename iterator_traits<_RandomAccessIterator>::value_type>)
421       __glibcxx_requires_valid_range(__first, __last);
422       __glibcxx_requires_irreflexive(__first, __last);
423       __glibcxx_requires_heap(__first, __last);
424 
425       std::__sort_heap(__first, __last,
426 		       __gnu_cxx::__ops::__iter_less_iter());
427     }
428 
429   /**
430    *  @brief  Sort a heap using comparison functor.
431    *  @param  __first  Start of heap.
432    *  @param  __last   End of heap.
433    *  @param  __comp   Comparison functor to use.
434    *  @ingroup heap_algorithms
435    *
436    *  This operation sorts the valid heap in the range [__first,__last).
437    *  Comparisons are made using __comp.
438   */
439   template<typename _RandomAccessIterator, typename _Compare>
440     inline void
441     sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
442 	      _Compare __comp)
443     {
444       // concept requirements
445       __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
446 	    _RandomAccessIterator>)
447       __glibcxx_requires_valid_range(__first, __last);
448       __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
449       __glibcxx_requires_heap_pred(__first, __last, __comp);
450 
451       std::__sort_heap(__first, __last,
452 		       __gnu_cxx::__ops::__iter_comp_iter(__comp));
453     }
454 
455 #if __cplusplus >= 201103L
456   /**
457    *  @brief  Search the end of a heap.
458    *  @param  __first  Start of range.
459    *  @param  __last   End of range.
460    *  @return  An iterator pointing to the first element not in the heap.
461    *  @ingroup heap_algorithms
462    *
463    *  This operation returns the last iterator i in [__first, __last) for which
464    *  the range [__first, i) is a heap.
465   */
466   template<typename _RandomAccessIterator>
467     inline _RandomAccessIterator
468     is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last)
469     {
470       // concept requirements
471       __glibcxx_function_requires(_RandomAccessIteratorConcept<
472 	    _RandomAccessIterator>)
473       __glibcxx_function_requires(_LessThanComparableConcept<
474 	    typename iterator_traits<_RandomAccessIterator>::value_type>)
475       __glibcxx_requires_valid_range(__first, __last);
476       __glibcxx_requires_irreflexive(__first, __last);
477 
478       return __first +
479 	std::__is_heap_until(__first, std::distance(__first, __last),
480 			     __gnu_cxx::__ops::__iter_less_iter());
481     }
482 
483   /**
484    *  @brief  Search the end of a heap using comparison functor.
485    *  @param  __first  Start of range.
486    *  @param  __last   End of range.
487    *  @param  __comp   Comparison functor to use.
488    *  @return  An iterator pointing to the first element not in the heap.
489    *  @ingroup heap_algorithms
490    *
491    *  This operation returns the last iterator i in [__first, __last) for which
492    *  the range [__first, i) is a heap.  Comparisons are made using __comp.
493   */
494   template<typename _RandomAccessIterator, typename _Compare>
495     inline _RandomAccessIterator
496     is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last,
497 		  _Compare __comp)
498     {
499       // concept requirements
500       __glibcxx_function_requires(_RandomAccessIteratorConcept<
501 	    _RandomAccessIterator>)
502       __glibcxx_requires_valid_range(__first, __last);
503       __glibcxx_requires_irreflexive_pred(__first, __last, __comp);
504 
505       return __first
506 	+ std::__is_heap_until(__first, std::distance(__first, __last),
507 			       __gnu_cxx::__ops::__iter_comp_iter(__comp));
508     }
509 
510   /**
511    *  @brief  Determines whether a range is a heap.
512    *  @param  __first  Start of range.
513    *  @param  __last   End of range.
514    *  @return  True if range is a heap, false otherwise.
515    *  @ingroup heap_algorithms
516   */
517   template<typename _RandomAccessIterator>
518     inline bool
519     is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
520     { return std::is_heap_until(__first, __last) == __last; }
521 
522   /**
523    *  @brief  Determines whether a range is a heap using comparison functor.
524    *  @param  __first  Start of range.
525    *  @param  __last   End of range.
526    *  @param  __comp   Comparison functor to use.
527    *  @return  True if range is a heap, false otherwise.
528    *  @ingroup heap_algorithms
529   */
530   template<typename _RandomAccessIterator, typename _Compare>
531     inline bool
532     is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
533 	    _Compare __comp)
534     { return std::is_heap_until(__first, __last, __comp) == __last; }
535 #endif
536 
537 _GLIBCXX_END_NAMESPACE_VERSION
538 } // namespace
539 
540 #endif /* _STL_HEAP_H */
541