forked from kodecocodes/swift-algorithm-club
-
Notifications
You must be signed in to change notification settings - Fork 1
/
HeapSort.swift
50 lines (40 loc) · 1.68 KB
/
HeapSort.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import Foundation
private func shiftDown<T>(_ elements: inout [T], _ index: Int, _ range: Range<Int>, by areInIncreasingOrder: (T, T) -> Bool) {
let countToIndex = elements.distance(from: range.lowerBound, to: index)
let countFromIndex = elements.distance(from: index, to: range.upperBound)
guard countToIndex + 1 < countFromIndex else { return }
let left = elements.index(index, offsetBy: countToIndex + 1)
var largest = index
if areInIncreasingOrder(elements[largest], elements[left]) {
largest = left
}
if countToIndex + 2 < countFromIndex {
let right = elements.index(after: left)
if areInIncreasingOrder(elements[largest], elements[right]) {
largest = right
}
}
if largest != index {
elements.swapAt(index, largest)
shiftDown(&elements, largest, range, by: areInIncreasingOrder)
}
}
private func heapify<T>(_ list: inout [T], _ range: Range<Int>, by areInIncreasingOrder: (T, T) -> Bool) {
let root = range.lowerBound
var node = list.index(root, offsetBy: list.distance(from: range.lowerBound, to: range.upperBound)/2)
while node != root {
list.formIndex(before: &node)
shiftDown(&list, node, range, by: areInIncreasingOrder)
}
}
public func heapsort<T>(for array: inout [T], range: Range<Int>, by areInIncreasingOrder: (T, T) -> Bool) {
var hi = range.upperBound
let lo = range.lowerBound
heapify(&array, range, by: areInIncreasingOrder)
array.formIndex(before: &hi)
while hi != lo {
array.swapAt(lo, hi)
shiftDown(&array, lo, lo..<hi, by: areInIncreasingOrder)
array.formIndex(before: &hi)
}
}