1 // Heap implementation -*- C++ -*- 2 3 // Copyright (C) 2001, 2004, 2005, 2006 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 2, 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 // You should have received a copy of the GNU General Public License along 17 // with this library; see the file COPYING. If not, write to the Free 18 // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 19 // USA. 20 21 // As a special exception, you may use this file as part of a free software 22 // library without restriction. Specifically, if other files instantiate 23 // templates or use macros or inline functions from this file, or you compile 24 // this file and link it with other files to produce an executable, this 25 // file does not by itself cause the resulting executable to be covered by 26 // the GNU General Public License. This exception does not however 27 // invalidate any other reasons why the executable file might be covered by 28 // the GNU General Public License. 29 30 /* 31 * 32 * Copyright (c) 1994 33 * Hewlett-Packard Company 34 * 35 * Permission to use, copy, modify, distribute and sell this software 36 * and its documentation for any purpose is hereby granted without fee, 37 * provided that the above copyright notice appear in all copies and 38 * that both that copyright notice and this permission notice appear 39 * in supporting documentation. Hewlett-Packard Company makes no 40 * representations about the suitability of this software for any 41 * purpose. It is provided "as is" without express or implied warranty. 42 * 43 * Copyright (c) 1997 44 * Silicon Graphics Computer Systems, Inc. 45 * 46 * Permission to use, copy, modify, distribute and sell this software 47 * and its documentation for any purpose is hereby granted without fee, 48 * provided that the above copyright notice appear in all copies and 49 * that both that copyright notice and this permission notice appear 50 * in supporting documentation. Silicon Graphics makes no 51 * representations about the suitability of this software for any 52 * purpose. It is provided "as is" without express or implied warranty. 53 */ 54 55 /** @file stl_heap.h 56 * This is an internal header file, included by other library headers. 57 * You should not attempt to use it directly. 58 */ 59 60 #ifndef _STL_HEAP_H 61 #define _STL_HEAP_H 1 62 63 #include <debug/debug.h> 64 65 _GLIBCXX_BEGIN_NAMESPACE(std) 66 67 // is_heap, a predicate testing whether or not a range is 68 // a heap. This function is an extension, not part of the C++ 69 // standard. 70 template<typename _RandomAccessIterator, typename _Distance> 71 bool 72 __is_heap(_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 false; 79 if ((__child & 1) == 0) 80 ++__parent; 81 } 82 return true; 83 } 84 85 template<typename _RandomAccessIterator, typename _Distance, 86 typename _StrictWeakOrdering> 87 bool 88 __is_heap(_RandomAccessIterator __first, _StrictWeakOrdering __comp, 89 _Distance __n) 90 { 91 _Distance __parent = 0; 92 for (_Distance __child = 1; __child < __n; ++__child) 93 { 94 if (__comp(__first[__parent], __first[__child])) 95 return false; 96 if ((__child & 1) == 0) 97 ++__parent; 98 } 99 return true; 100 } 101 102 template<typename _RandomAccessIterator> 103 bool 104 __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) 105 { return std::__is_heap(__first, std::distance(__first, __last)); } 106 107 template<typename _RandomAccessIterator, typename _StrictWeakOrdering> 108 bool 109 __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, 110 _StrictWeakOrdering __comp) 111 { return std::__is_heap(__first, __comp, std::distance(__first, __last)); } 112 113 // Heap-manipulation functions: push_heap, pop_heap, make_heap, sort_heap. 114 115 template<typename _RandomAccessIterator, typename _Distance, typename _Tp> 116 void 117 __push_heap(_RandomAccessIterator __first, 118 _Distance __holeIndex, _Distance __topIndex, _Tp __value) 119 { 120 _Distance __parent = (__holeIndex - 1) / 2; 121 while (__holeIndex > __topIndex && *(__first + __parent) < __value) 122 { 123 *(__first + __holeIndex) = *(__first + __parent); 124 __holeIndex = __parent; 125 __parent = (__holeIndex - 1) / 2; 126 } 127 *(__first + __holeIndex) = __value; 128 } 129 130 /** 131 * @brief Push an element onto a heap. 132 * @param first Start of heap. 133 * @param last End of heap + element. 134 * @ingroup heap 135 * 136 * This operation pushes the element at last-1 onto the valid heap over the 137 * range [first,last-1). After completion, [first,last) is a valid heap. 138 */ 139 template<typename _RandomAccessIterator> 140 inline void 141 push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) 142 { 143 typedef typename iterator_traits<_RandomAccessIterator>::value_type 144 _ValueType; 145 typedef typename iterator_traits<_RandomAccessIterator>::difference_type 146 _DistanceType; 147 148 // concept requirements 149 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< 150 _RandomAccessIterator>) 151 __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>) 152 __glibcxx_requires_valid_range(__first, __last); 153 // __glibcxx_requires_heap(__first, __last - 1); 154 155 std::__push_heap(__first, _DistanceType((__last - __first) - 1), 156 _DistanceType(0), _ValueType(*(__last - 1))); 157 } 158 159 template<typename _RandomAccessIterator, typename _Distance, typename _Tp, 160 typename _Compare> 161 void 162 __push_heap(_RandomAccessIterator __first, _Distance __holeIndex, 163 _Distance __topIndex, _Tp __value, _Compare __comp) 164 { 165 _Distance __parent = (__holeIndex - 1) / 2; 166 while (__holeIndex > __topIndex 167 && __comp(*(__first + __parent), __value)) 168 { 169 *(__first + __holeIndex) = *(__first + __parent); 170 __holeIndex = __parent; 171 __parent = (__holeIndex - 1) / 2; 172 } 173 *(__first + __holeIndex) = __value; 174 } 175 176 /** 177 * @brief Push an element onto a heap using comparison functor. 178 * @param first Start of heap. 179 * @param last End of heap + element. 180 * @param comp Comparison functor. 181 * @ingroup heap 182 * 183 * This operation pushes the element at last-1 onto the valid heap over the 184 * range [first,last-1). After completion, [first,last) is a valid heap. 185 * Compare operations are performed using comp. 186 */ 187 template<typename _RandomAccessIterator, typename _Compare> 188 inline void 189 push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, 190 _Compare __comp) 191 { 192 typedef typename iterator_traits<_RandomAccessIterator>::value_type 193 _ValueType; 194 typedef typename iterator_traits<_RandomAccessIterator>::difference_type 195 _DistanceType; 196 197 // concept requirements 198 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< 199 _RandomAccessIterator>) 200 __glibcxx_requires_valid_range(__first, __last); 201 __glibcxx_requires_heap_pred(__first, __last - 1, __comp); 202 203 std::__push_heap(__first, _DistanceType((__last - __first) - 1), 204 _DistanceType(0), _ValueType(*(__last - 1)), __comp); 205 } 206 207 template<typename _RandomAccessIterator, typename _Distance, typename _Tp> 208 void 209 __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex, 210 _Distance __len, _Tp __value) 211 { 212 const _Distance __topIndex = __holeIndex; 213 _Distance __secondChild = 2 * __holeIndex + 2; 214 while (__secondChild < __len) 215 { 216 if (*(__first + __secondChild) < *(__first + (__secondChild - 1))) 217 __secondChild--; 218 *(__first + __holeIndex) = *(__first + __secondChild); 219 __holeIndex = __secondChild; 220 __secondChild = 2 * (__secondChild + 1); 221 } 222 if (__secondChild == __len) 223 { 224 *(__first + __holeIndex) = *(__first + (__secondChild - 1)); 225 __holeIndex = __secondChild - 1; 226 } 227 std::__push_heap(__first, __holeIndex, __topIndex, __value); 228 } 229 230 template<typename _RandomAccessIterator, typename _Tp> 231 inline void 232 __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, 233 _RandomAccessIterator __result, _Tp __value) 234 { 235 typedef typename iterator_traits<_RandomAccessIterator>::difference_type 236 _Distance; 237 *__result = *__first; 238 std::__adjust_heap(__first, _Distance(0), _Distance(__last - __first), 239 __value); 240 } 241 242 /** 243 * @brief Pop an element off a heap. 244 * @param first Start of heap. 245 * @param last End of heap. 246 * @ingroup heap 247 * 248 * This operation pops the top of the heap. The elements first and last-1 249 * are swapped and [first,last-1) is made into a heap. 250 */ 251 template<typename _RandomAccessIterator> 252 inline void 253 pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) 254 { 255 typedef typename iterator_traits<_RandomAccessIterator>::value_type 256 _ValueType; 257 258 // concept requirements 259 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< 260 _RandomAccessIterator>) 261 __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>) 262 __glibcxx_requires_valid_range(__first, __last); 263 __glibcxx_requires_heap(__first, __last); 264 265 std::__pop_heap(__first, __last - 1, __last - 1, 266 _ValueType(*(__last - 1))); 267 } 268 269 template<typename _RandomAccessIterator, typename _Distance, 270 typename _Tp, typename _Compare> 271 void 272 __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex, 273 _Distance __len, _Tp __value, _Compare __comp) 274 { 275 const _Distance __topIndex = __holeIndex; 276 _Distance __secondChild = 2 * __holeIndex + 2; 277 while (__secondChild < __len) 278 { 279 if (__comp(*(__first + __secondChild), 280 *(__first + (__secondChild - 1)))) 281 __secondChild--; 282 *(__first + __holeIndex) = *(__first + __secondChild); 283 __holeIndex = __secondChild; 284 __secondChild = 2 * (__secondChild + 1); 285 } 286 if (__secondChild == __len) 287 { 288 *(__first + __holeIndex) = *(__first + (__secondChild - 1)); 289 __holeIndex = __secondChild - 1; 290 } 291 std::__push_heap(__first, __holeIndex, __topIndex, __value, __comp); 292 } 293 294 template<typename _RandomAccessIterator, typename _Tp, typename _Compare> 295 inline void 296 __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, 297 _RandomAccessIterator __result, _Tp __value, _Compare __comp) 298 { 299 typedef typename iterator_traits<_RandomAccessIterator>::difference_type 300 _Distance; 301 *__result = *__first; 302 std::__adjust_heap(__first, _Distance(0), _Distance(__last - __first), 303 __value, __comp); 304 } 305 306 /** 307 * @brief Pop an element off a heap using comparison functor. 308 * @param first Start of heap. 309 * @param last End of heap. 310 * @param comp Comparison functor to use. 311 * @ingroup heap 312 * 313 * This operation pops the top of the heap. The elements first and last-1 314 * are swapped and [first,last-1) is made into a heap. Comparisons are 315 * made using comp. 316 */ 317 template<typename _RandomAccessIterator, typename _Compare> 318 inline void 319 pop_heap(_RandomAccessIterator __first, 320 _RandomAccessIterator __last, _Compare __comp) 321 { 322 // concept requirements 323 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< 324 _RandomAccessIterator>) 325 __glibcxx_requires_valid_range(__first, __last); 326 __glibcxx_requires_heap_pred(__first, __last, __comp); 327 328 typedef typename iterator_traits<_RandomAccessIterator>::value_type 329 _ValueType; 330 std::__pop_heap(__first, __last - 1, __last - 1, 331 _ValueType(*(__last - 1)), __comp); 332 } 333 334 /** 335 * @brief Construct a heap over a range. 336 * @param first Start of heap. 337 * @param last End of heap. 338 * @ingroup heap 339 * 340 * This operation makes the elements in [first,last) into a heap. 341 */ 342 template<typename _RandomAccessIterator> 343 void 344 make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) 345 { 346 typedef typename iterator_traits<_RandomAccessIterator>::value_type 347 _ValueType; 348 typedef typename iterator_traits<_RandomAccessIterator>::difference_type 349 _DistanceType; 350 351 // concept requirements 352 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< 353 _RandomAccessIterator>) 354 __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>) 355 __glibcxx_requires_valid_range(__first, __last); 356 357 if (__last - __first < 2) 358 return; 359 360 const _DistanceType __len = __last - __first; 361 _DistanceType __parent = (__len - 2) / 2; 362 while (true) 363 { 364 std::__adjust_heap(__first, __parent, __len, 365 _ValueType(*(__first + __parent))); 366 if (__parent == 0) 367 return; 368 __parent--; 369 } 370 } 371 372 /** 373 * @brief Construct a heap over a range using comparison functor. 374 * @param first Start of heap. 375 * @param last End of heap. 376 * @param comp Comparison functor to use. 377 * @ingroup heap 378 * 379 * This operation makes the elements in [first,last) into a heap. 380 * Comparisons are made using comp. 381 */ 382 template<typename _RandomAccessIterator, typename _Compare> 383 inline void 384 make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, 385 _Compare __comp) 386 { 387 typedef typename iterator_traits<_RandomAccessIterator>::value_type 388 _ValueType; 389 typedef typename iterator_traits<_RandomAccessIterator>::difference_type 390 _DistanceType; 391 392 // concept requirements 393 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< 394 _RandomAccessIterator>) 395 __glibcxx_requires_valid_range(__first, __last); 396 397 if (__last - __first < 2) 398 return; 399 400 const _DistanceType __len = __last - __first; 401 _DistanceType __parent = (__len - 2) / 2; 402 while (true) 403 { 404 std::__adjust_heap(__first, __parent, __len, 405 _ValueType(*(__first + __parent)), __comp); 406 if (__parent == 0) 407 return; 408 __parent--; 409 } 410 } 411 412 /** 413 * @brief Sort a heap. 414 * @param first Start of heap. 415 * @param last End of heap. 416 * @ingroup heap 417 * 418 * This operation sorts the valid heap in the range [first,last). 419 */ 420 template<typename _RandomAccessIterator> 421 void 422 sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) 423 { 424 // concept requirements 425 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< 426 _RandomAccessIterator>) 427 __glibcxx_function_requires(_LessThanComparableConcept< 428 typename iterator_traits<_RandomAccessIterator>::value_type>) 429 __glibcxx_requires_valid_range(__first, __last); 430 // __glibcxx_requires_heap(__first, __last); 431 432 while (__last - __first > 1) 433 std::pop_heap(__first, _RandomAccessIterator(__last--)); 434 } 435 436 /** 437 * @brief Sort a heap using comparison functor. 438 * @param first Start of heap. 439 * @param last End of heap. 440 * @param comp Comparison functor to use. 441 * @ingroup heap 442 * 443 * This operation sorts the valid heap in the range [first,last). 444 * Comparisons are made using comp. 445 */ 446 template<typename _RandomAccessIterator, typename _Compare> 447 void 448 sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, 449 _Compare __comp) 450 { 451 // concept requirements 452 __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< 453 _RandomAccessIterator>) 454 __glibcxx_requires_valid_range(__first, __last); 455 __glibcxx_requires_heap_pred(__first, __last, __comp); 456 457 while (__last - __first > 1) 458 std::pop_heap(__first, _RandomAccessIterator(__last--), __comp); 459 } 460 461 _GLIBCXX_END_NAMESPACE 462 463 #endif /* _STL_HEAP_H */ 464