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

[Heap] Convert min() and max() to properties #328

Merged
merged 2 commits into from
Jan 30, 2024
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
10 changes: 5 additions & 5 deletions Documentation/Heap.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ This works by adding the new element into the end of the backing array and then
You can also insert a sequence of elements into a `Heap`:

```swift
var heap = Heap((0..<10))
heap.insert(contentsOf: (20...100).shuffled())
var heap = Heap(0 ..< 10)
heap.insert(contentsOf: (20 ... 100).shuffled())
heap.insert(contentsOf: [-5, -6, -8, -12, -3])
```

Expand All @@ -63,9 +63,9 @@ heap.insert(contentsOf: [-5, -6, -8, -12, -3])
As mentioned earlier, the smallest and largest elements can be queried in constant time:

```swift
var heap = Heap((1...20))
let min = heap.min() // min = 1
let max = heap.max() // max = 20
var heap = Heap(1 ... 20)
let min = heap.min // 1
let max = heap.max // 20
```

In a min-max heap, the smallest element is stored at index 0 in the backing array; the largest element is stored at either index 1 or index 2, the first max level in the heap (so to look up the largest, we compare the two and return the larger one).
Expand Down
8 changes: 4 additions & 4 deletions Sources/HeapModule/Heap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
///
/// var queue: Heap<Int> = [3, 4, 1, 2]
/// queue.insert(0)
/// print(queue.min()) // 0
/// print(queue.min) // 0
/// print(queue.popMax()) // 4
/// print(queue.max()) // 3
/// print(queue.max) // 3
///
/// `Heap` implements the min-max heap data structure, based on
/// [Atkinson et al. 1986].
Expand Down Expand Up @@ -117,15 +117,15 @@ extension Heap {
///
/// - Complexity: O(1)
@inlinable
public func min() -> Element? {
public var min: Element? {
_storage.first
}

/// Returns the element with the highest priority, if available.
///
/// - Complexity: O(1)
@inlinable
public func max() -> Element? {
public var max: Element? {
_storage.withUnsafeBufferPointer { buffer in
guard buffer.count > 2 else {
// If count is 0, `last` will return `nil`
Expand Down
92 changes: 46 additions & 46 deletions Tests/HeapTests/HeapTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,12 @@ final class HeapTests: CollectionTestCase {

heap.insert(contentsOf: (21...50).shuffled())
expectEqual(heap.count, 38)
expectEqual(heap.max(), 50)
expectEqual(heap.min(), 2)
expectEqual(heap.max, 50)
expectEqual(heap.min, 2)

heap.insert(contentsOf: [-10, -9, -8, -7, -6, -5].shuffled())
expectEqual(heap.count, 44)
expectEqual(heap.min(), -10)
expectEqual(heap.min, -10)
}

func test_insert_contentsOf_withSequenceFunction() {
Expand Down Expand Up @@ -165,36 +165,36 @@ final class HeapTests: CollectionTestCase {

func test_min() {
var heap = Heap<Int>()
expectNil(heap.min())
expectNil(heap.min)

heap.insert(5)
expectEqual(5, heap.min())
expectEqual(5, heap.min)

heap.insert(12)
expectEqual(5, heap.min())
expectEqual(5, heap.min)

heap.insert(2)
expectEqual(2, heap.min())
expectEqual(2, heap.min)

heap.insert(1)
expectEqual(1, heap.min())
expectEqual(1, heap.min)
}

func test_max() {
var heap = Heap<Int>()
expectNil(heap.max())
expectNil(heap.max)

heap.insert(42)
expectEqual(42, heap.max())
expectEqual(42, heap.max)

heap.insert(20)
expectEqual(42, heap.max())
expectEqual(42, heap.max)

heap.insert(63)
expectEqual(63, heap.max())
expectEqual(63, heap.max)

heap.insert(90)
expectEqual(90, heap.max())
expectEqual(90, heap.max)
}

func test_popMin() {
Expand Down Expand Up @@ -345,133 +345,133 @@ final class HeapTests: CollectionTestCase {
var heap = Heap(stride(from: 0, through: 27, by: 3).shuffled())
expectEqual(
heap.itemsInAscendingOrder(), [0, 3, 6, 9, 12, 15, 18, 21, 24, 27])
expectEqual(heap.min(), 0)
expectEqual(heap.min, 0)

// No change
heap.replaceMin(with: 0)
expectEqual(
heap.itemsInAscendingOrder(), [0, 3, 6, 9, 12, 15, 18, 21, 24, 27])
expectEqual(heap.min(), 0)
expectEqual(heap.min, 0)

// Even smaller
heap.replaceMin(with: -1)
expectEqual(
heap.itemsInAscendingOrder(), [-1, 3, 6, 9, 12, 15, 18, 21, 24, 27])
expectEqual(heap.min(), -1)
expectEqual(heap.min, -1)

// Larger, but not enough to usurp
heap.replaceMin(with: 2)
expectEqual(
heap.itemsInAscendingOrder(), [2, 3, 6, 9, 12, 15, 18, 21, 24, 27])
expectEqual(heap.min(), 2)
expectEqual(heap.min, 2)

// Larger, moving another element to be the smallest
heap.replaceMin(with: 5)
expectEqual(
heap.itemsInAscendingOrder(), [3, 5, 6, 9, 12, 15, 18, 21, 24, 27])
expectEqual(heap.min(), 3)
expectEqual(heap.min, 3)
}

func test_maximumReplacement() {
var heap = Heap(stride(from: 0, through: 27, by: 3).shuffled())
expectEqual(
heap.itemsInAscendingOrder(), [0, 3, 6, 9, 12, 15, 18, 21, 24, 27])
expectEqual(heap.max(), 27)
expectEqual(heap.max, 27)

// No change
heap.replaceMax(with: 27)
expectEqual(
heap.itemsInAscendingOrder(), [0, 3, 6, 9, 12, 15, 18, 21, 24, 27])
expectEqual(heap.max(), 27)
expectEqual(heap.max, 27)

// Even larger
heap.replaceMax(with: 28)
expectEqual(
heap.itemsInAscendingOrder(), [0, 3, 6, 9, 12, 15, 18, 21, 24, 28])
expectEqual(heap.max(), 28)
expectEqual(heap.max, 28)

// Smaller, but not enough to usurp
heap.replaceMax(with: 26)
expectEqual(
heap.itemsInAscendingOrder(), [0, 3, 6, 9, 12, 15, 18, 21, 24, 26])
expectEqual(heap.max(), 26)
expectEqual(heap.max, 26)

// Smaller, moving another element to be the largest
heap.replaceMax(with: 23)
expectEqual(
heap.itemsInAscendingOrder(), [0, 3, 6, 9, 12, 15, 18, 21, 23, 24])
expectEqual(heap.max(), 24)
expectEqual(heap.max, 24)

// Check the finer details. As these peek into the stored structure, they
// may need to be updated whenever the internal format changes.
var heap2 = Heap(raw: [1])
expectEqual(heap2.max(), 1)
expectEqual(heap2.max, 1)
expectEqual(Array(heap2.unordered), [1])
expectEqual(heap2.replaceMax(with: 2), 1)
expectEqual(heap2.max(), 2)
expectEqual(heap2.max, 2)
expectEqual(Array(heap2.unordered), [2])

heap2 = Heap(raw: [1, 2])
expectEqual(heap2.max(), 2)
expectEqual(heap2.max, 2)
expectEqual(Array(heap2.unordered), [1, 2])
expectEqual(heap2.replaceMax(with: 3), 2)
expectEqual(heap2.max(), 3)
expectEqual(heap2.max, 3)
expectEqual(Array(heap2.unordered), [1, 3])
expectEqual(heap2.replaceMax(with: 0), 3)
expectEqual(heap2.max(), 1)
expectEqual(heap2.max, 1)
expectEqual(Array(heap2.unordered), [0, 1])

heap2 = Heap(raw: [5, 20, 31, 16, 8, 7, 18])
expectEqual(heap2.max(), 31)
expectEqual(heap2.max, 31)
expectEqual(Array(heap2.unordered), [5, 20, 31, 16, 8, 7, 18])
expectEqual(heap2.replaceMax(with: 29), 31)
expectEqual(Array(heap2.unordered), [5, 20, 29, 16, 8, 7, 18])
expectEqual(heap2.max(), 29)
expectEqual(heap2.max, 29)
expectEqual(heap2.replaceMax(with: 19), 29)
expectEqual(Array(heap2.unordered), [5, 20, 19, 16, 8, 7, 18])
expectEqual(heap2.max(), 20)
expectEqual(heap2.max, 20)
expectEqual(heap2.replaceMax(with: 15), 20)
expectEqual(Array(heap2.unordered), [5, 16, 19, 15, 8, 7, 18])
expectEqual(heap2.max(), 19)
expectEqual(heap2.max, 19)
expectEqual(heap2.replaceMax(with: 4), 19)
expectEqual(Array(heap2.unordered), [4, 16, 18, 15, 8, 7, 5])
expectEqual(heap2.max(), 18)
expectEqual(heap2.max, 18)
}

// MARK: -

func test_min_struct() {
var heap = Heap<Task>()
expectNil(heap.min())
expectNil(heap.min)

let firstTask = Task(name: "Do something", priority: 10)
heap.insert(firstTask)
expectEqual(heap.min(), firstTask)
expectEqual(heap.min, firstTask)

let higherPriorityTask = Task(name: "Urgent", priority: 100)
heap.insert(higherPriorityTask)
expectEqual(heap.min(), firstTask)
expectEqual(heap.min, firstTask)

let lowerPriorityTask = Task(name: "Get this done today", priority: 1)
heap.insert(lowerPriorityTask)
expectEqual(heap.min(), lowerPriorityTask)
expectEqual(heap.min, lowerPriorityTask)
}

func test_max_struct() {
var heap = Heap<Task>()
expectNil(heap.max())
expectNil(heap.max)

let firstTask = Task(name: "Do something", priority: 10)
heap.insert(firstTask)
expectEqual(heap.max(), firstTask)
expectEqual(heap.max, firstTask)

let lowerPriorityTask = Task(name: "Get this done today", priority: 1)
heap.insert(lowerPriorityTask)
expectEqual(heap.max(), firstTask)
expectEqual(heap.max, firstTask)

let higherPriorityTask = Task(name: "Urgent", priority: 100)
heap.insert(higherPriorityTask)
expectEqual(heap.max(), higherPriorityTask)
expectEqual(heap.max, higherPriorityTask)
}

func test_popMin_struct() {
Expand Down Expand Up @@ -516,7 +516,7 @@ final class HeapTests: CollectionTestCase {

func test_initializer_fromCollection() {
var heap = Heap((1...20).shuffled())
expectEqual(heap.max(), 20)
expectEqual(heap.max, 20)

expectEqual(heap.popMin(), 1)
expectEqual(heap.popMax(), 20)
Expand Down Expand Up @@ -565,12 +565,12 @@ final class HeapTests: CollectionTestCase {
let input = (0 ..< c).shuffled(using: &rng)
let heap = Heap(input)
if c > 0 {
expectEqual(heap.min(), 0)
expectEqual(heap.max(), c - 1)
expectEqual(heap.min, 0)
expectEqual(heap.max, c - 1)
expectEqualElements(heap.itemsInAscendingOrder(), 0 ..< c)
} else {
expectNil(heap.min())
expectNil(heap.max())
expectNil(heap.min)
expectNil(heap.max)
expectEqualElements(heap.itemsInAscendingOrder(), [])
}
}
Expand Down