Skip to content

[stdlib][fix] Fixed wrong sorting behavior #19107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions stdlib/public/core/Sort.swift
Original file line number Diff line number Diff line change
Expand Up @@ -486,14 +486,14 @@ extension MutableCollection where Self: RandomAccessCollection {
within range: Range<Index>,
by areInIncreasingOrder: (Element, Element) throws -> Bool
) rethrows {
var i = idx
var countToIndex = distance(from: range.lowerBound, to: i)
var countFromIndex = distance(from: i, to: range.upperBound)
var idx = idx
var countToIndex = distance(from: range.lowerBound, to: idx)
var countFromIndex = distance(from: idx, to: range.upperBound)
// Check if left child is within bounds. If not, stop iterating, because
// there are no children of the given node in the heap.
while countToIndex + 1 < countFromIndex {
let left = index(i, offsetBy: countToIndex + 1)
var largest = i
let left = index(idx, offsetBy: countToIndex + 1)
var largest = idx
if try areInIncreasingOrder(self[largest], self[left]) {
largest = left
}
Expand All @@ -504,13 +504,13 @@ extension MutableCollection where Self: RandomAccessCollection {
largest = right
}
}
// If a child is bigger than the current node, swap them and continue sifting
// down.
if largest != i {
// If a child is bigger than the current node, swap them and continue
// sifting down.
if largest != idx {
swapAt(idx, largest)
i = largest
countToIndex = distance(from: range.lowerBound, to: i)
countFromIndex = distance(from: i, to: range.upperBound)
idx = largest
countToIndex = distance(from: range.lowerBound, to: idx)
countFromIndex = distance(from: idx, to: range.upperBound)
} else {
break
}
Expand Down Expand Up @@ -540,7 +540,8 @@ extension MutableCollection where Self: RandomAccessCollection {
}

@inlinable
internal mutating func _heapSort(
public // @testable
mutating func _heapSort(
within range: Range<Index>,
by areInIncreasingOrder: (Element, Element) throws -> Bool
) rethrows {
Expand Down
47 changes: 47 additions & 0 deletions validation-test/stdlib/Algorithm.swift
Original file line number Diff line number Diff line change
Expand Up @@ -253,5 +253,52 @@ Algorithm.test("sort3/stable")
})
}

Algorithm.test("heapSort") {
// This function generate next permutation of 0-1 using long arithmetics
// approach.
func addOne(to num: inout [Int]) {

if num.isEmpty {
return
}
// Consider our num array reflects a binary integer.
// Here we are trying to add one to it.
var i = num.index(before: num.endIndex)
var carrier = 1

while carrier != 0 {
let b = num[i] + carrier
// Updating i's bit.
num[i] = b % 2
// Recalculate new carrier.
carrier = b / 2

// If the length of number was n, we don't want to create new number with
// length n + 1 in this test.
if i == num.startIndex {
break
} else {
num.formIndex(before: &i)
}
}
} // addOne end.

// Test binary number size.
let numberLength = 21
var binaryNumber = [Int](repeating: 0, count: numberLength)

// We are testing sort on all permutations off 0-1s of size `numberLength`
// except the all 1's case (Its equals to all 0's case).
while !binaryNumber.allSatisfy({ $0 == 1 }) {
var buffer = binaryNumber

buffer._heapSort(within: buffer.startIndex..<buffer.endIndex, by: <)

expectTrue(isSorted(buffer, by: <))

addOne(to: &binaryNumber)
}
}

runAllTests()