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  --__last;
295  std::__pop_heap(__first, __last, __last);
296  }
297 
298  template<typename _RandomAccessIterator, typename _Distance,
299  typename _Tp, typename _Compare>
300  void
301  __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
302  _Distance __len, _Tp __value, _Compare __comp)
303  {
304  const _Distance __topIndex = __holeIndex;
305  _Distance __secondChild = __holeIndex;
306  while (__secondChild < (__len - 1) / 2)
307  {
308  __secondChild = 2 * (__secondChild + 1);
309  if (__comp(*(__first + __secondChild),
310  *(__first + (__secondChild - 1))))
311  __secondChild--;
312  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
313  __holeIndex = __secondChild;
314  }
315  if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2)
316  {
317  __secondChild = 2 * (__secondChild + 1);
318  *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first
319  + (__secondChild - 1)));
320  __holeIndex = __secondChild - 1;
321  }
322  std::__push_heap(__first, __holeIndex, __topIndex,
323  _GLIBCXX_MOVE(__value), __comp);
324  }
325 
326  template<typename _RandomAccessIterator, typename _Compare>
327  inline void
328  __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
329  _RandomAccessIterator __result, _Compare __comp)
330  {
331  typedef typename iterator_traits<_RandomAccessIterator>::value_type
332  _ValueType;
333  typedef typename iterator_traits<_RandomAccessIterator>::difference_type
334  _DistanceType;
335 
336  _ValueType __value = _GLIBCXX_MOVE(*__result);
337  *__result = _GLIBCXX_MOVE(*__first);
338  std::__adjust_heap(__first, _DistanceType(0),
339  _DistanceType(__last - __first),
340  _GLIBCXX_MOVE(__value), __comp);
341  }
342 
343  /**
344  * @brief Pop an element off a heap using comparison functor.
345  * @param __first Start of heap.
346  * @param __last End of heap.
347  * @param __comp Comparison functor to use.
348  * @ingroup heap_algorithms
349  *
350  * This operation pops the top of the heap. The elements __first
351  * and __last-1 are swapped and [__first,__last-1) is made into a
352  * heap. Comparisons are made using comp.
353  */
354  template<typename _RandomAccessIterator, typename _Compare>
355  inline void
356  pop_heap(_RandomAccessIterator __first,
357  _RandomAccessIterator __last, _Compare __comp)
358  {
359  // concept requirements
360  __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
361  _RandomAccessIterator>)
362  __glibcxx_requires_valid_range(__first, __last);
363  __glibcxx_requires_non_empty_range(__first, __last);
364  __glibcxx_requires_heap_pred(__first, __last, __comp);
365 
366  --__last;
367  std::__pop_heap(__first, __last, __last, __comp);
368  }
369 
370  /**
371  * @brief Construct a heap over a range.
372  * @param __first Start of heap.
373  * @param __last End of heap.
374  * @ingroup heap_algorithms
375  *
376  * This operation makes the elements in [__first,__last) into a heap.
377  */
378  template<typename _RandomAccessIterator>
379  void
380  make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
381  {
382  typedef typename iterator_traits<_RandomAccessIterator>::value_type
383  _ValueType;
384  typedef typename iterator_traits<_RandomAccessIterator>::difference_type
385  _DistanceType;
386 
387  // concept requirements
388  __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
389  _RandomAccessIterator>)
390  __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
391  __glibcxx_requires_valid_range(__first, __last);
392 
393  if (__last - __first < 2)
394  return;
395 
396  const _DistanceType __len = __last - __first;
397  _DistanceType __parent = (__len - 2) / 2;
398  while (true)
399  {
400  _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
401  std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value));
402  if (__parent == 0)
403  return;
404  __parent--;
405  }
406  }
407 
408  /**
409  * @brief Construct a heap over a range using comparison functor.
410  * @param __first Start of heap.
411  * @param __last End of heap.
412  * @param __comp Comparison functor to use.
413  * @ingroup heap_algorithms
414  *
415  * This operation makes the elements in [__first,__last) into a heap.
416  * Comparisons are made using __comp.
417  */
418  template<typename _RandomAccessIterator, typename _Compare>
419  void
420  make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
421  _Compare __comp)
422  {
423  typedef typename iterator_traits<_RandomAccessIterator>::value_type
424  _ValueType;
425  typedef typename iterator_traits<_RandomAccessIterator>::difference_type
426  _DistanceType;
427 
428  // concept requirements
429  __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
430  _RandomAccessIterator>)
431  __glibcxx_requires_valid_range(__first, __last);
432 
433  if (__last - __first < 2)
434  return;
435 
436  const _DistanceType __len = __last - __first;
437  _DistanceType __parent = (__len - 2) / 2;
438  while (true)
439  {
440  _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
441  std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value),
442  __comp);
443  if (__parent == 0)
444  return;
445  __parent--;
446  }
447  }
448 
449  /**
450  * @brief Sort a heap.
451  * @param __first Start of heap.
452  * @param __last End of heap.
453  * @ingroup heap_algorithms
454  *
455  * This operation sorts the valid heap in the range [__first,__last).
456  */
457  template<typename _RandomAccessIterator>
458  void
459  sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
460  {
461  // concept requirements
462  __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
463  _RandomAccessIterator>)
464  __glibcxx_function_requires(_LessThanComparableConcept<
465  typename iterator_traits<_RandomAccessIterator>::value_type>)
466  __glibcxx_requires_valid_range(__first, __last);
467  __glibcxx_requires_heap(__first, __last);
468 
469  while (__last - __first > 1)
470  {
471  --__last;
472  std::__pop_heap(__first, __last, __last);
473  }
474  }
475 
476  /**
477  * @brief Sort a heap using comparison functor.
478  * @param __first Start of heap.
479  * @param __last End of heap.
480  * @param __comp Comparison functor to use.
481  * @ingroup heap_algorithms
482  *
483  * This operation sorts the valid heap in the range [__first,__last).
484  * Comparisons are made using __comp.
485  */
486  template<typename _RandomAccessIterator, typename _Compare>
487  void
488  sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
489  _Compare __comp)
490  {
491  // concept requirements
492  __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
493  _RandomAccessIterator>)
494  __glibcxx_requires_valid_range(__first, __last);
495  __glibcxx_requires_heap_pred(__first, __last, __comp);
496 
497  while (__last - __first > 1)
498  {
499  --__last;
500  std::__pop_heap(__first, __last, __last, __comp);
501  }
502  }
503 
504 #if __cplusplus >= 201103L
505  /**
506  * @brief Search the end of a heap.
507  * @param __first Start of range.
508  * @param __last End of range.
509  * @return An iterator pointing to the first element not in the heap.
510  * @ingroup heap_algorithms
511  *
512  * This operation returns the last iterator i in [__first, __last) for which
513  * the range [__first, i) is a heap.
514  */
515  template<typename _RandomAccessIterator>
516  inline _RandomAccessIterator
517  is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last)
518  {
519  // concept requirements
520  __glibcxx_function_requires(_RandomAccessIteratorConcept<
521  _RandomAccessIterator>)
522  __glibcxx_function_requires(_LessThanComparableConcept<
523  typename iterator_traits<_RandomAccessIterator>::value_type>)
524  __glibcxx_requires_valid_range(__first, __last);
525 
526  return __first + std::__is_heap_until(__first, std::distance(__first,
527  __last));
528  }
529 
530  /**
531  * @brief Search the end of a heap using comparison functor.
532  * @param __first Start of range.
533  * @param __last End of range.
534  * @param __comp Comparison functor to use.
535  * @return An iterator pointing to the first element not in the heap.
536  * @ingroup heap_algorithms
537  *
538  * This operation returns the last iterator i in [__first, __last) for which
539  * the range [__first, i) is a heap. Comparisons are made using __comp.
540  */
541  template<typename _RandomAccessIterator, typename _Compare>
542  inline _RandomAccessIterator
543  is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last,
544  _Compare __comp)
545  {
546  // concept requirements
547  __glibcxx_function_requires(_RandomAccessIteratorConcept<
548  _RandomAccessIterator>)
549  __glibcxx_requires_valid_range(__first, __last);
550 
551  return __first + std::__is_heap_until(__first, std::distance(__first,
552  __last),
553  __comp);
554  }
555 
556  /**
557  * @brief Determines whether a range is a heap.
558  * @param __first Start of range.
559  * @param __last End of range.
560  * @return True if range is a heap, false otherwise.
561  * @ingroup heap_algorithms
562  */
563  template<typename _RandomAccessIterator>
564  inline bool
565  is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
566  { return std::is_heap_until(__first, __last) == __last; }
567 
568  /**
569  * @brief Determines whether a range is a heap using comparison functor.
570  * @param __first Start of range.
571  * @param __last End of range.
572  * @param __comp Comparison functor to use.
573  * @return True if range is a heap, false otherwise.
574  * @ingroup heap_algorithms
575  */
576  template<typename _RandomAccessIterator, typename _Compare>
577  inline bool
578  is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
579  _Compare __comp)
580  { return std::is_heap_until(__first, __last, __comp) == __last; }
581 #endif
582 
583 _GLIBCXX_END_NAMESPACE_VERSION
584 } // namespace
585 
586 #endif /* _STL_HEAP_H */