Skip to content

Commit aa34eb2

Browse files
kchibisovairspeedswift
authored andcommitted
[stdlib][fix] Fixed wrong sorting behavior (#19107)
* [stdlib] Fixed wrong sorting behavior * [stdlib] Refactored siftDown. * [stdlib][test] Added tests for heapSort.
1 parent e3f3e93 commit aa34eb2

File tree

2 files changed

+60
-12
lines changed

2 files changed

+60
-12
lines changed

stdlib/public/core/Sort.swift

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -486,14 +486,14 @@ extension MutableCollection where Self: RandomAccessCollection {
486486
within range: Range<Index>,
487487
by areInIncreasingOrder: (Element, Element) throws -> Bool
488488
) rethrows {
489-
var i = idx
490-
var countToIndex = distance(from: range.lowerBound, to: i)
491-
var countFromIndex = distance(from: i, to: range.upperBound)
489+
var idx = idx
490+
var countToIndex = distance(from: range.lowerBound, to: idx)
491+
var countFromIndex = distance(from: idx, to: range.upperBound)
492492
// Check if left child is within bounds. If not, stop iterating, because
493493
// there are no children of the given node in the heap.
494494
while countToIndex + 1 < countFromIndex {
495-
let left = index(i, offsetBy: countToIndex + 1)
496-
var largest = i
495+
let left = index(idx, offsetBy: countToIndex + 1)
496+
var largest = idx
497497
if try areInIncreasingOrder(self[largest], self[left]) {
498498
largest = left
499499
}
@@ -504,13 +504,13 @@ extension MutableCollection where Self: RandomAccessCollection {
504504
largest = right
505505
}
506506
}
507-
// If a child is bigger than the current node, swap them and continue sifting
508-
// down.
509-
if largest != i {
507+
// If a child is bigger than the current node, swap them and continue
508+
// sifting down.
509+
if largest != idx {
510510
swapAt(idx, largest)
511-
i = largest
512-
countToIndex = distance(from: range.lowerBound, to: i)
513-
countFromIndex = distance(from: i, to: range.upperBound)
511+
idx = largest
512+
countToIndex = distance(from: range.lowerBound, to: idx)
513+
countFromIndex = distance(from: idx, to: range.upperBound)
514514
} else {
515515
break
516516
}
@@ -540,7 +540,8 @@ extension MutableCollection where Self: RandomAccessCollection {
540540
}
541541

542542
@inlinable
543-
internal mutating func _heapSort(
543+
public // @testable
544+
mutating func _heapSort(
544545
within range: Range<Index>,
545546
by areInIncreasingOrder: (Element, Element) throws -> Bool
546547
) rethrows {

validation-test/stdlib/Algorithm.swift

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,5 +253,52 @@ Algorithm.test("sort3/stable")
253253
})
254254
}
255255

256+
Algorithm.test("heapSort") {
257+
// This function generate next permutation of 0-1 using long arithmetics
258+
// approach.
259+
func addOne(to num: inout [Int]) {
260+
261+
if num.isEmpty {
262+
return
263+
}
264+
// Consider our num array reflects a binary integer.
265+
// Here we are trying to add one to it.
266+
var i = num.index(before: num.endIndex)
267+
var carrier = 1
268+
269+
while carrier != 0 {
270+
let b = num[i] + carrier
271+
// Updating i's bit.
272+
num[i] = b % 2
273+
// Recalculate new carrier.
274+
carrier = b / 2
275+
276+
// If the length of number was n, we don't want to create new number with
277+
// length n + 1 in this test.
278+
if i == num.startIndex {
279+
break
280+
} else {
281+
num.formIndex(before: &i)
282+
}
283+
}
284+
} // addOne end.
285+
286+
// Test binary number size.
287+
let numberLength = 21
288+
var binaryNumber = [Int](repeating: 0, count: numberLength)
289+
290+
// We are testing sort on all permutations off 0-1s of size `numberLength`
291+
// except the all 1's case (Its equals to all 0's case).
292+
while !binaryNumber.allSatisfy({ $0 == 1 }) {
293+
var buffer = binaryNumber
294+
295+
buffer._heapSort(within: buffer.startIndex..<buffer.endIndex, by: <)
296+
297+
expectTrue(isSorted(buffer, by: <))
298+
299+
addOne(to: &binaryNumber)
300+
}
301+
}
302+
256303
runAllTests()
257304

0 commit comments

Comments
 (0)