[libc-commits] [libc] [libc][stdlib] Optimize number of comparisons in heap_sort (PR #232602)
via libc-commits
libc-commits at lists.llvm.org
Thu Oct 15 22:57:38 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: Kuan-Wei Chiu (visitorckw)
<details>
<summary>Changes</summary>
The current heapsort implementation in the siftdown function follows the standard textbook version, necessitating two comparisons at each level. Transitioning to the Bottom-up heapsort version allows us to decrease the required comparisons to just one per level. On average, this modification significantly reduces the comparison count from 2nlog2(n) - 3n + o(n) to nlog2(n) + 0.37*n + o(n).
Refs:
BOTTOM-UP-HEAPSORT, a new variant of HEAPSORT beating, on an average,
QUICKSORT (if n is not very small)
Ingo Wegener
Theoretical Computer Science, 118(1); Pages 81-98, 13 September 1993
https://doi.org/10.1016/0304-3975(93)90364-Y
---
Full diff: https://github.com/llvm/llvm-project/pull/232602.diff
1 Files Affected:
- (modified) libc/src/stdlib/heap_sort.h (+19-14)
``````````diff
diff --git a/libc/src/stdlib/heap_sort.h b/libc/src/stdlib/heap_sort.h
index b9699776df89c..b9341266cb404 100644
--- a/libc/src/stdlib/heap_sort.h
+++ b/libc/src/stdlib/heap_sort.h
@@ -37,20 +37,25 @@ LIBC_INLINE void heap_sort(const A &array, const F &is_less) {
}
// Sift start down the heap.
- size_t root = start;
- while (left_child(root) < end) {
- size_t child = left_child(root);
- // If there are two children, set child to the greater.
- if ((child + 1 < end) && is_less(array.get(child), array.get(child + 1)))
- ++child;
-
- // If the root is less than the greater child
- if (!is_less(array.get(root), array.get(child)))
- break;
-
- // Swap the root with the greater child and continue sifting down.
- array.swap(root, child);
- root = child;
+ size_t i, j;
+
+ // Find the sift-down path all the way to the leaves.
+ for (i = start; j = left_child(i), j + 1 < end;)
+ i = is_less(array.get(j), array.get(j + 1)) ? (j + 1) : j;
+
+ // Special case for the last leaf with no sibling.
+ if (j < end)
+ i = j;
+
+ // Backtrack to the correct location.
+ while (i != start && is_less(array.get(i), array.get(start)))
+ i = (i - 1) / 2;
+
+ // Shift the element into its correct place.
+ j = i;
+ while (i != start) {
+ i = (i - 1) / 2;
+ array.swap(i, j);
}
}
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/232602
More information about the libc-commits
mailing list