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