Skip to content

Commit 9c5f9ce

Browse files
kchibisovairspeedswift
authored andcommitted
[stdlib][QoI] Replace recursion in sort _siftDown with Iteration (#18629)
* stdlib: replace recursion in _siftDown with iteration Iterative approach removes recursion overhead. Therefore performance of sorting will be improved
1 parent 38e88d8 commit 9c5f9ce

File tree

1 file changed

+26
-27
lines changed

1 file changed

+26
-27
lines changed

stdlib/public/core/Sort.swift

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -516,35 +516,34 @@ internal func _siftDown<C: MutableCollection & RandomAccessCollection>(
516516
subRange range: Range<C.Index>,
517517
by areInIncreasingOrder: (C.Element, C.Element) throws -> Bool
518518
) rethrows {
519-
520-
let countToIndex = elements.distance(from: range.lowerBound, to: index)
521-
let countFromIndex = elements.distance(from: index, to: range.upperBound)
522-
// Check if left child is within bounds. If not, return, because there are
519+
var i = index
520+
var countToIndex = elements.distance(from: range.lowerBound, to: i)
521+
var countFromIndex = elements.distance(from: i, to: range.upperBound)
522+
// Check if left child is within bounds. If not, stop iterating, because there are
523523
// no children of the given node in the heap.
524-
if countToIndex + 1 >= countFromIndex {
525-
return
526-
}
527-
let left = elements.index(index, offsetBy: countToIndex + 1)
528-
var largest = index
529-
if (try areInIncreasingOrder(elements[largest], elements[left])) {
530-
largest = left
531-
}
532-
// Check if right child is also within bounds before trying to examine it.
533-
if countToIndex + 2 < countFromIndex {
534-
let right = elements.index(after: left)
535-
if (try areInIncreasingOrder(elements[largest], elements[right])) {
536-
largest = right
524+
while countToIndex + 1 < countFromIndex {
525+
let left = elements.index(i, offsetBy: countToIndex + 1)
526+
var largest = i
527+
if try areInIncreasingOrder(elements[largest], elements[left]) {
528+
largest = left
529+
}
530+
// Check if right child is also within bounds before trying to examine it.
531+
if countToIndex + 2 < countFromIndex {
532+
let right = elements.index(after: left)
533+
if try areInIncreasingOrder(elements[largest], elements[right]) {
534+
largest = right
535+
}
536+
}
537+
// If a child is bigger than the current node, swap them and continue sifting
538+
// down.
539+
if largest != i {
540+
elements.swapAt(index, largest)
541+
i = largest
542+
countToIndex = elements.distance(from: range.lowerBound, to: i)
543+
countFromIndex = elements.distance(from: i, to: range.upperBound)
544+
} else {
545+
break
537546
}
538-
}
539-
// If a child is bigger than the current node, swap them and continue sifting
540-
// down.
541-
if largest != index {
542-
elements.swapAt(index, largest)
543-
try _siftDown(
544-
&elements,
545-
index: largest,
546-
subRange: range
547-
, by: areInIncreasingOrder)
548547
}
549548
}
550549

0 commit comments

Comments
 (0)