[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