Skip to content
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

Add "sortedPrefix(_:by)" to Collection #9

Merged
merged 31 commits into from
Dec 4, 2020
Merged
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
5429d3b
Add partial sort algorithm
rakaramos Oct 8, 2020
4362197
Add in place partial sorting
rockbruno Oct 9, 2020
f299df1
Guide docs
rockbruno Oct 9, 2020
6cd2870
Use Indexes
rockbruno Oct 9, 2020
63b2dd0
Merge pull request #1 from rakaramos/guide
rakaramos Oct 9, 2020
88216e1
Add partial sort tests
rakaramos Oct 9, 2020
afe7111
Indent up to 80 columns
rakaramos Oct 9, 2020
4652ae7
Fix heapify stopping before it should
rockbruno Oct 9, 2020
37d494a
Update PartialSort.md
rockbruno Oct 9, 2020
83d5f1e
Update PartialSort.md
rockbruno Oct 9, 2020
bf31ba1
Update PartialSort.swift
rockbruno Oct 9, 2020
acb3583
Cleaning up iterators logic
rockbruno Oct 9, 2020
6227bd8
Update PartialSort.swift
rockbruno Oct 9, 2020
d4a2e6b
Cleaning docs
rockbruno Oct 9, 2020
62ee6f2
Change implementation and name
rakaramos Oct 21, 2020
f674851
DocDocs
rockbruno Oct 21, 2020
5bdea96
Merge remote-tracking branch 'origin/fix-algo' into docdocs
rockbruno Oct 21, 2020
dd15b5a
Docs
rockbruno Oct 21, 2020
7ac3915
Merge pull request #3 from rakaramos/docdocs
rockbruno Oct 21, 2020
c68537f
Docs
rockbruno Oct 21, 2020
e8504fd
Optimize
rockbruno Oct 21, 2020
36e9a39
Fix header and remove assert
rakaramos Oct 28, 2020
1d22ef9
Add more tests (#4)
rakaramos Oct 31, 2020
62096e1
Update PartialSortTests.swift
rockbruno Oct 31, 2020
d0c1ccd
Merge pull request #5 from rakaramos/rockbruno-patch-1
rockbruno Oct 31, 2020
23bf863
Update Sources/Algorithms/PartialSort.swift
rockbruno Nov 1, 2020
379609b
Update Sources/Algorithms/PartialSort.swift
rockbruno Nov 1, 2020
435a38c
Update Sources/Algorithms/PartialSort.swift
rockbruno Nov 1, 2020
70973a2
Documentation fixes
rockbruno Nov 1, 2020
70a263c
Add tests for massive inputs
rockbruno Dec 2, 2020
1d3dcaf
isLastElement
rockbruno Dec 2, 2020
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
89 changes: 89 additions & 0 deletions Sources/Algorithms/PartialSort.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import Foundation
rakaramos marked this conversation as resolved.
Show resolved Hide resolved

private final class Heap<T> {
rakaramos marked this conversation as resolved.
Show resolved Hide resolved

typealias Comparator = (T,T) -> Bool

private var elements: [T]
private let priority: Comparator

init<S: Sequence>(elements: S, priority: @escaping Comparator) where S.Element == T {
self.priority = priority
self.elements = Array(elements)
if elements.isEmpty == false {
for i in stride(from: (count / 2) - 1, to: -1, by: -1) {
siftDown(i)
}
}
}

private func leftChildIndex(of index: Int) -> Int {
return (2 * index) + 1
}

private func rightChild(of index: Int) -> Int {
return (2 * index) + 2
}

private func parentIndex(of index: Int) -> Int {
return (index - 1) / 2
}

private func isHigherPriority(_ a: Int, _ b: Int) -> Bool {
return priority(elements[a], elements[b])
}

private func highestPriorityIndex(of index: Int) -> Int {
let left = highestPriorityIndex(of: index, and: leftChildIndex(of: index))
let right = highestPriorityIndex(of: index, and: rightChild(of: index))
return highestPriorityIndex(of: left, and: right)
}

private func highestPriorityIndex(of parent: Int, and child: Int) -> Int {
guard child < elements.count else {
return parent
}
guard isHigherPriority(child, parent) else {
return parent
}
return child
}

func dequeue() -> T? {
guard elements.count > 0 else {
return nil
}
elements.swapAt(0, elements.count - 1)
let element = elements.popLast()
siftDown(0)
return element
}

private func siftDown(_ i: Int) {
let indexToSwap = highestPriorityIndex(of: i)
guard indexToSwap != i else {
return
}
elements.swapAt(indexToSwap, i)
siftDown(indexToSwap)
}
}

extension Collection {
rakaramos marked this conversation as resolved.
Show resolved Hide resolved
func partiallySorted(_ count: Int, by: @escaping (Element, Element) -> Bool) -> [Element] {
rakaramos marked this conversation as resolved.
Show resolved Hide resolved
assert(count >= 0 && count < self.count, "Are you crazy?")
let heap = Heap<Element>(elements: self, priority: by)
return [Element](unsafeUninitializedCapacity: count) { buffer, initializedCount in
for i in 0..<count {
buffer[i] = heap.dequeue()!
}
initializedCount = count
}
}
}

extension Collection where Element: Comparable {
func partiallySorted(_ count: Int) -> [Element] {
return partiallySorted(count, by: <)
}
}