libstdc++
stl_heap.h
Go to the documentation of this file.
1 // Heap implementation -*- C++ -*-
2 
3 // Copyright (C) 2001-2013 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 
61 namespace std _GLIBCXX_VISIBILITY(default)
62 {
63 _GLIBCXX_BEGIN_NAMESPACE_VERSION
64 
65  /**
66  * @defgroup heap_algorithms Heap
67  * @ingroup sorting_algorithms
68  */
69 
70  template<typename _RandomAccessIterator, typename _Distance>
71  _Distance
72  __is_heap_until(_RandomAccessIterator __first, _Distance __n)
73  {
74  _Distance __parent = 0;
75  for (_Distance __child = 1; __child < __n; ++__child)
76  {
77  if (__first[__parent] < __first[__child])
78  return __child;
79  if ((__child & 1) == 0)
80  ++__parent;
81  }
82  return __n;
83  }
84 
85  template<typename _RandomAccessIterator, typename _Distance,
86  typename _Compare>
87  _Distance
88  __is_heap_until(_RandomAccessIterator __first, _Distance __n,
89  _Compare __comp)
90  {
91  _Distance __parent = 0;
92  for (_Distance __child = 1; __child < __n; ++__child)
93  {
94  if (__comp(__first[__parent], __first[__child]))
95  return __child;
96  if ((__child & 1) == 0)
97  ++__parent;
98  }
99  return __n;
100  }
101 
102  // __is_heap, a predicate testing whether or not a range is a heap.
103  // This function is an extension, not part of the C++ standard.
104  template<typename _RandomAccessIterator, typename _Distance>
105  inline bool
106  __is_heap(_RandomAccessIterator __first, _Distance __n)
107  { return std::__is_heap_until(__first, __n) == __n; }
108 
109  template<typename _RandomAccessIterator, typename _Compare,
110  typename _Distance>
111  inline bool
112  __is_heap(_RandomAccessIterator __first, _Compare __comp, _Distance __n)
113  { return std::__is_heap_until(__first, __n, __comp) == __n; }
114 
115  template<typename _RandomAccessIterator>
116  inline bool
117  __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
118  { return std::__is_heap(__first, std::distance(__first, __last)); }
119 
120  template<typename _RandomAccessIterator, typename _Compare>
121  inline bool
122  __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
123  _Compare __comp)
124  { return std::__is_heap(__first, __comp, std::distance(__first, __last)); }
125 
126  // Heap-manipulation functions: push_heap, pop_heap, make_heap, sort_heap,
127  // + is_heap and is_heap_until in C++0x.
128 
129  template<typename _RandomAccessIterator, typename _Distance, typename _Tp>
130  void
131  __push_heap(_RandomAccessIterator __first,
132  _Distance __holeIndex, _Distance __topIndex, _Tp __value)
133  {
134  _Distance __parent = (__holeIndex - 1) / 2;
135  while (__holeIndex > __topIndex && *(__first + __parent) < __value)
136  {
137  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
138  __holeIndex = __parent;
139  __parent = (__holeIndex - 1) / 2;
140  }
141  *(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
142  }
143 
144  /**
145  * @brief Push an element onto a heap.
146  * @param __first Start of heap.
147  * @param __last End of heap + element.
148  * @ingroup heap_algorithms
149  *
150  * This operation pushes the element at last-1 onto the valid heap
151  * over the range [__first,__last-1). After completion,
152  * [__first,__last) is a valid heap.
153  */
154  template<typename _RandomAccessIterator>
155  inline void
156  push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
157  {
158  typedef typename iterator_traits<_RandomAccessIterator>::value_type
159  _ValueType;
160  typedef typename iterator_traits<_RandomAccessIterator>::difference_type
161  _DistanceType;
162 
163  // concept requirements
164  __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
165  _RandomAccessIterator>)
166  __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
167  __glibcxx_requires_valid_range(__first, __last);
168  __glibcxx_requires_heap(__first, __last - 1);
169 
170  _ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
171  std::__push_heap(__first, _DistanceType((__last - __first) - 1),
172  _DistanceType(0), _GLIBCXX_MOVE(__value));
173  }
174 
175  template<typename _RandomAccessIterator, typename _Distance, typename _Tp,
176  typename _Compare>
177  void
178  __push_heap(_RandomAccessIterator __first, _Distance __holeIndex,
179  _Distance __topIndex, _Tp __value, _Compare __comp)
180  {
181  _Distance __parent = (__holeIndex - 1) / 2;
182  while (__holeIndex > __topIndex
183  && __comp(*(__first + __parent), __value))
184  {
185  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
186  __holeIndex = __parent;
187  __parent = (__holeIndex - 1) / 2;
188  }
189  *(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
190  }
191 
192  /**
193  * @brief Push an element onto a heap using comparison functor.
194  * @param __first Start of heap.
195  * @param __last End of heap + element.
196  * @param __comp Comparison functor.
197  * @ingroup heap_algorithms
198  *
199  * This operation pushes the element at __last-1 onto the valid
200  * heap over the range [__first,__last-1). After completion,
201  * [__first,__last) is a valid heap. Compare operations are
202  * performed using comp.
203  */
204  template<typename _RandomAccessIterator, typename _Compare>
205  inline void
206  push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
207  _Compare __comp)
208  {
209  typedef typename iterator_traits<_RandomAccessIterator>::value_type
210  _ValueType;
211  typedef typename iterator_traits<_RandomAccessIterator>::difference_type
212  _DistanceType;
213 
214  // concept requirements
215  __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
216  _RandomAccessIterator>)
217  __glibcxx_requires_valid_range(__first, __last);
218  __glibcxx_requires_heap_pred(__first, __last - 1, __comp);
219 
220  _ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
221  std::__push_heap(__first, _DistanceType((__last - __first) - 1),
222  _DistanceType(0), _GLIBCXX_MOVE(__value), __comp);
223  }
224 
225  template<typename _RandomAccessIterator, typename _Distance, typename _Tp>
226  void
227  __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
228  _Distance __len, _Tp __value)
229  {
230  const _Distance __topIndex = __holeIndex;
231  _Distance __secondChild = __holeIndex;
232  while (__secondChild < (__len - 1) / 2)
233  {
234  __secondChild = 2 * (__secondChild + 1);
235  if (*(__first + __secondChild) < *(__first + (__secondChild - 1)))
236  __secondChild--;
237  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
238  __holeIndex = __secondChild;
239  }
240  if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
241  {
242  __secondChild = 2 * (__secondChild + 1);
243  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first
244  + (__secondChild - 1)));
245  __holeIndex = __secondChild - 1;
246  }
247  std::__push_heap(__first, __holeIndex, __topIndex,
248  _GLIBCXX_MOVE(__value));
249  }
250 
251  template<typename _RandomAccessIterator>
252  inline void
253  __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
254  _RandomAccessIterator __result)
255  {
256  typedef typename iterator_traits<_RandomAccessIterator>::value_type
257  _ValueType;
258  typedef typename iterator_traits<_RandomAccessIterator>::difference_type
259  _DistanceType;
260 
261  _ValueType __value = _GLIBCXX_MOVE(*__result);
262  *__result = _GLIBCXX_MOVE(*__first);
263  std::__adjust_heap(__first, _DistanceType(0),
264  _DistanceType(__last - __first),
265  _GLIBCXX_MOVE(__value));
266  }
267 
268  /**
269  * @brief Pop an element off a heap.
270  * @param __first Start of heap.
271  * @param __last End of heap.
272  * @pre [__first, __last) is a valid, non-empty range.
273  * @ingroup heap_algorithms
274  *
275  * This operation pops the top of the heap. The elements __first
276  * and __last-1 are swapped and [__first,__last-1) is made into a
277  * heap.
278  */
279  template<typename _RandomAccessIterator>
280  inline void
281  pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
282  {
283  typedef typename iterator_traits<_RandomAccessIterator>::value_type
284  _ValueType;
285 
286  // concept requirements
287  __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
288  _RandomAccessIterator>)
289  __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
290  __glibcxx_requires_non_empty_range(__first, __last);
291  __glibcxx_requires_valid_range(__first, __last);
292  __glibcxx_requires_heap(__first, __last);
293 
294  if (__last - __first > 1)
295  {
296  --__last;
297  std::__pop_heap(__first, __last, __last);
298  }
299  }
300 
301  template<typename _RandomAccessIterator, typename _Distance,
302  typename _Tp, typename _Compare>
303  void
304  __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
305  _Distance __len, _Tp __value, _Compare __comp)
306  {
307  const _Distance __topIndex = __holeIndex;
308  _Distance __secondChild = __holeIndex;
309  while (__secondChild < (__len - 1) / 2)
310  {
311  __secondChild = 2 * (__secondChild + 1);
312  if (__comp(*(__first + __secondChild),
313  *(__first + (__secondChild - 1))))
314  __secondChild--;
315  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
316  __holeIndex = __secondChild;
317  }
318  if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
319  {
320  __secondChild = 2 * (__secondChild + 1);
321  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first
322  + (__secondChild - 1)));
323  __holeIndex = __secondChild - 1;
324  }
325  std::__push_heap(__first, __holeIndex, __topIndex,
326  _GLIBCXX_MOVE(__value), __comp);
327  }
328 
329  template<typename _RandomAccessIterator, typename _Compare>
330  inline void
331  __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
332  _RandomAccessIterator __result, _Compare __comp)
333  {
334  typedef typename iterator_traits<_RandomAccessIterator>::value_type
335  _ValueType;
336  typedef typename iterator_traits<_RandomAccessIterator>::difference_type
337  _DistanceType;
338 
339  _ValueType __value = _GLIBCXX_MOVE(*__result);
340  *__result = _GLIBCXX_MOVE(*__first);
341  std::__adjust_heap(__first, _DistanceType(0),
342  _DistanceType(__last - __first),
343  _GLIBCXX_MOVE(__value), __comp);
344  }
345 
346  /**
347  * @brief Pop an element off a heap using comparison functor.
348  * @param __first Start of heap.
349  * @param __last End of heap.
350  * @param __comp Comparison functor to use.
351  * @ingroup heap_algorithms
352  *
353  * This operation pops the top of the heap. The elements __first
354  * and __last-1 are swapped and [__first,__last-1) is made into a
355  * heap. Comparisons are made using comp.
356  */
357  template<typename _RandomAccessIterator, typename _Compare>
358  inline void
359  pop_heap(_RandomAccessIterator __first,
360  _RandomAccessIterator __last, _Compare __comp)
361  {
362  // concept requirements
363  __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
364  _RandomAccessIterator>)
365  __glibcxx_requires_valid_range(__first, __last);
366  __glibcxx_requires_non_empty_range(__first, __last);
367  __glibcxx_requires_heap_pred(__first, __last, __comp);
368 
369  if (__last - __first > 1)
370  {
371  --__last;
372  std::__pop_heap(__first, __last, __last, __comp);
373  }
374  }
375 
376  /**
377  * @brief Construct a heap over a range.
378  * @param __first Start of heap.
379  * @param __last End of heap.
380  * @ingroup heap_algorithms
381  *
382  * This operation makes the elements in [__first,__last) into a heap.
383  */
384  template<typename _RandomAccessIterator>
385  void
386  make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
387  {
388  typedef typename iterator_traits<_RandomAccessIterator>::value_type
389  _ValueType;
390  typedef typename iterator_traits<_RandomAccessIterator>::difference_type
391  _DistanceType;
392 
393  // concept requirements
394  __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
395  _RandomAccessIterator>)
396  __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
397  __glibcxx_requires_valid_range(__first, __last);
398 
399  if (__last - __first < 2)
400  return;
401 
402  const _DistanceType __len = __last - __first;
403  _DistanceType __parent = (__len - 2) / 2;
404  while (true)
405  {
406  _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
407  std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value));
408  if (__parent == 0)
409  return;
410  __parent--;
411  }
412  }
413 
414  /**
415  * @brief Construct a heap over a range using comparison functor.
416  * @param __first Start of heap.
417  * @param __last End of heap.
418  * @param __comp Comparison functor to use.
419  * @ingroup heap_algorithms
420  *
421  * This operation makes the elements in [__first,__last) into a heap.
422  * Comparisons are made using __comp.
423  */
424  template<typename _RandomAccessIterator, typename _Compare>
425  void
426  make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
427  _Compare __comp)
428  {
429  typedef typename iterator_traits<_RandomAccessIterator>::value_type
430  _ValueType;
431  typedef typename iterator_traits<_RandomAccessIterator>::difference_type
432  _DistanceType;
433 
434  // concept requirements
435  __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
436  _RandomAccessIterator>)
437  __glibcxx_requires_valid_range(__first, __last);
438 
439  if (__last - __first < 2)
440  return;
441 
442  const _DistanceType __len = __last - __first;
443  _DistanceType __parent = (__len - 2) / 2;
444  while (true)
445  {
446  _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
447  std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value),
448  __comp);
449  if (__parent == 0)
450  return;
451  __parent--;
452  }
453  }
454 
455  /**
456  * @brief Sort a heap.
457  * @param __first Start of heap.
458  * @param __last End of heap.
459  * @ingroup heap_algorithms
460  *
461  * This operation sorts the valid heap in the range [__first,__last).
462  */
463  template<typename _RandomAccessIterator>
464  void
465  sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
466  {
467  // concept requirements
468  __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
469  _RandomAccessIterator>)
470  __glibcxx_function_requires(_LessThanComparableConcept<
471  typename iterator_traits<_RandomAccessIterator>::value_type>)
472  __glibcxx_requires_valid_range(__first, __last);
473  __glibcxx_requires_heap(__first, __last);
474 
475  while (__last - __first > 1)
476  {
477  --__last;
478  std::__pop_heap(__first, __last, __last);
479  }
480  }
481 
482  /**
483  * @brief Sort a heap using comparison functor.
484  * @param __first Start of heap.
485  * @param __last End of heap.
486  * @param __comp Comparison functor to use.
487  * @ingroup heap_algorithms
488  *
489  * This operation sorts the valid heap in the range [__first,__last).
490  * Comparisons are made using __comp.
491  */
492  template<typename _RandomAccessIterator, typename _Compare>
493  void
494  sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
495  _Compare __comp)
496  {
497  // concept requirements
498  __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
499  _RandomAccessIterator>)
500  __glibcxx_requires_valid_range(__first, __last);
501  __glibcxx_requires_heap_pred(__first, __last, __comp);
502 
503  while (__last - __first > 1)
504  {
505  --__last;
506  std::__pop_heap(__first, __last, __last, __comp);
507  }
508  }
509 
510 #if __cplusplus >= 201103L
511  /**
512  * @brief Search the end of a heap.
513  * @param __first Start of range.
514  * @param __last End of range.
515  * @return An iterator pointing to the first element not in the heap.
516  * @ingroup heap_algorithms
517  *
518  * This operation returns the last iterator i in [__first, __last) for which
519  * the range [__first, i) is a heap.
520  */
521  template<typename _RandomAccessIterator>
522  inline _RandomAccessIterator
523  is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last)
524  {
525  // concept requirements
526  __glibcxx_function_requires(_RandomAccessIteratorConcept<
527  _RandomAccessIterator>)
528  __glibcxx_function_requires(_LessThanComparableConcept<
529  typename iterator_traits<_RandomAccessIterator>::value_type>)
530  __glibcxx_requires_valid_range(__first, __last);
531 
532  return __first + std::__is_heap_until(__first, std::distance(__first,
533  __last));
534  }
535 
536  /**
537  * @brief Search the end of a heap using comparison functor.
538  * @param __first Start of range.
539  * @param __last End of range.
540  * @param __comp Comparison functor to use.
541  * @return An iterator pointing to the first element not in the heap.
542  * @ingroup heap_algorithms
543  *
544  * This operation returns the last iterator i in [__first, __last) for which
545  * the range [__first, i) is a heap. Comparisons are made using __comp.
546  */
547  template<typename _RandomAccessIterator, typename _Compare>
548  inline _RandomAccessIterator
549  is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last,
550  _Compare __comp)
551  {
552  // concept requirements
553  __glibcxx_function_requires(_RandomAccessIteratorConcept<
554  _RandomAccessIterator>)
555  __glibcxx_requires_valid_range(__first, __last);
556 
557  return __first + std::__is_heap_until(__first, std::distance(__first,
558  __last),
559  __comp);
560  }
561 
562  /**
563  * @brief Determines whether a range is a heap.
564  * @param __first Start of range.
565  * @param __last End of range.
566  * @return True if range is a heap, false otherwise.
567  * @ingroup heap_algorithms
568  */
569  template<typename _RandomAccessIterator>
570  inline bool
571  is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
572  { return std::is_heap_until(__first, __last) == __last; }
573 
574  /**
575  * @brief Determines whether a range is a heap using comparison functor.
576  * @param __first Start of range.
577  * @param __last End of range.
578  * @param __comp Comparison functor to use.
579  * @return True if range is a heap, false otherwise.
580  * @ingroup heap_algorithms
581  */
582  template<typename _RandomAccessIterator, typename _Compare>
583  inline bool
584  is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
585  _Compare __comp)
586  { return std::is_heap_until(__first, __last, __comp) == __last; }
587 #endif
588 
589 _GLIBCXX_END_NAMESPACE_VERSION
590 } // namespace
591 
592 #endif /* _STL_HEAP_H */
iterator_traits< _InputIterator >::difference_type distance(_InputIterator __first, _InputIterator __last)
A generalization of pointer arithmetic.
ISO C++ entities toplevel namespace is std.
_RandomAccessIterator is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
Search the end of a heap using comparison functor.
Definition: stl_heap.h:549