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