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 61namespace 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 */ 593