xref: /llvm-project/libc/src/stdlib/heap_sort.h (revision a738d81cd2822698539b0482af48d49d91ea5a2e)
1a6d2da8bSlntue //===-- Implementation of heap sort -----------------------------*- C++ -*-===//
2a6d2da8bSlntue //
3a6d2da8bSlntue // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a6d2da8bSlntue // See https://llvm.org/LICENSE.txt for license information.
5a6d2da8bSlntue // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a6d2da8bSlntue //
7a6d2da8bSlntue //===----------------------------------------------------------------------===//
8a6d2da8bSlntue 
9a6d2da8bSlntue #ifndef LLVM_LIBC_SRC_STDLIB_HEAP_SORT_H
10a6d2da8bSlntue #define LLVM_LIBC_SRC_STDLIB_HEAP_SORT_H
11a6d2da8bSlntue 
12a6d2da8bSlntue #include "src/__support/CPP/cstddef.h"
13a6d2da8bSlntue #include "src/stdlib/qsort_data.h"
14a6d2da8bSlntue 
15a6d2da8bSlntue namespace LIBC_NAMESPACE_DECL {
16a6d2da8bSlntue namespace internal {
17a6d2da8bSlntue 
18a6d2da8bSlntue // A simple in-place heapsort implementation.
19a6d2da8bSlntue // Follow the implementation in https://en.wikipedia.org/wiki/Heapsort.
20a6d2da8bSlntue 
21*a738d81cSLukas Bergdoll template <typename A, typename F>
22*a738d81cSLukas Bergdoll LIBC_INLINE void heap_sort(const A &array, const F &is_less) {
23*a738d81cSLukas Bergdoll   size_t end = array.len();
24a6d2da8bSlntue   size_t start = end / 2;
25a6d2da8bSlntue 
26*a738d81cSLukas Bergdoll   const auto left_child = [](size_t i) -> size_t { return 2 * i + 1; };
27a6d2da8bSlntue 
28a6d2da8bSlntue   while (end > 1) {
29a6d2da8bSlntue     if (start > 0) {
30a6d2da8bSlntue       // Select the next unheapified element to sift down.
31a6d2da8bSlntue       --start;
32a6d2da8bSlntue     } else {
33a6d2da8bSlntue       // Extract the max element of the heap, moving a leaf to root to be sifted
34a6d2da8bSlntue       // down.
35a6d2da8bSlntue       --end;
36a6d2da8bSlntue       array.swap(0, end);
37a6d2da8bSlntue     }
38a6d2da8bSlntue 
39a6d2da8bSlntue     // Sift start down the heap.
40a6d2da8bSlntue     size_t root = start;
41a6d2da8bSlntue     while (left_child(root) < end) {
42a6d2da8bSlntue       size_t child = left_child(root);
43a6d2da8bSlntue       // If there are two children, set child to the greater.
44*a738d81cSLukas Bergdoll       if ((child + 1 < end) && is_less(array.get(child), array.get(child + 1)))
45a6d2da8bSlntue         ++child;
46a6d2da8bSlntue 
47a6d2da8bSlntue       // If the root is less than the greater child
48*a738d81cSLukas Bergdoll       if (!is_less(array.get(root), array.get(child)))
49a6d2da8bSlntue         break;
50a6d2da8bSlntue 
51a6d2da8bSlntue       // Swap the root with the greater child and continue sifting down.
52a6d2da8bSlntue       array.swap(root, child);
53a6d2da8bSlntue       root = child;
54a6d2da8bSlntue     }
55a6d2da8bSlntue   }
56a6d2da8bSlntue }
57a6d2da8bSlntue 
58a6d2da8bSlntue } // namespace internal
59a6d2da8bSlntue } // namespace LIBC_NAMESPACE_DECL
60a6d2da8bSlntue 
61a6d2da8bSlntue #endif // LLVM_LIBC_SRC_STDLIB_HEAP_SORT_H
62