Skip to content

Commit 92f67b5

Browse files
committed
- Adopted discussed improvements
- Made nodes and some other methods internal, so that extensions like HeapSort can use them. This fixes the HeapSort algorithm as well as the tests for both.
1 parent e30467b commit 92f67b5

File tree

3 files changed

+38
-64
lines changed

3 files changed

+38
-64
lines changed

Diff for: Heap Sort/HeapSort.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
extension Heap {
22
public mutating func sort() -> [T] {
3-
for i in stride(from: (elements.count - 1), through: 1, by: -1) {
4-
elements.swapAt(0, i)
5-
shiftDown(0, heapSize: i)
3+
for i in stride(from: (nodes.count - 1), through: 1, by: -1) {
4+
nodes.swapAt(0, i)
5+
shiftDown(from: 0, until: i)
66
}
7-
return elements
7+
return nodes
88
}
99
}
1010

Diff for: Heap/Heap.swift

+24-31
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
public struct Heap<T> {
77

88
/** The array that stores the heap's nodes. */
9-
private(set) var nodes = [T]()
9+
internal var nodes = [T]()
1010

1111
/**
1212
* Determines how to compare two nodes in the heap.
@@ -33,14 +33,14 @@ public struct Heap<T> {
3333
*/
3434
public init(array: [T], sort: @escaping (T, T) -> Bool) {
3535
self.orderCriteria = sort
36-
buildHeap(fromArray: array)
36+
configureHeap(from: array)
3737
}
3838

3939
/**
40-
* Creates the max-heap or min-heap from an array, in a bottom-up manner.
40+
* Configures the max-heap or min-heap from an array, in a bottom-up manner.
4141
* Performance: This runs pretty much in O(n).
4242
*/
43-
private mutating func buildHeap(fromArray array: [T]) {
43+
private mutating func configureHeap(from array: [T]) {
4444
nodes = array
4545
for i in stride(from: (nodes.count/2-1), through: 0, by: -1) {
4646
shiftDown(i)
@@ -59,7 +59,7 @@ public struct Heap<T> {
5959
* Returns the index of the parent of the element at index i.
6060
* The element at index 0 is the root of the tree and has no parent.
6161
*/
62-
@inline(__always) func parentIndex(ofIndex i: Int) -> Int {
62+
@inline(__always) internal func parentIndex(ofIndex i: Int) -> Int {
6363
return (i - 1) / 2
6464
}
6565

@@ -68,7 +68,7 @@ public struct Heap<T> {
6868
* Note that this index can be greater than the heap size, in which case
6969
* there is no left child.
7070
*/
71-
@inline(__always) func leftChildIndex(ofIndex i: Int) -> Int {
71+
@inline(__always) internal func leftChildIndex(ofIndex i: Int) -> Int {
7272
return 2*i + 1
7373
}
7474

@@ -77,7 +77,7 @@ public struct Heap<T> {
7777
* Note that this index can be greater than the heap size, in which case
7878
* there is no right child.
7979
*/
80-
@inline(__always) func rightChildIndex(ofIndex i: Int) -> Int {
80+
@inline(__always) internal func rightChildIndex(ofIndex i: Int) -> Int {
8181
return 2*i + 2
8282
}
8383

@@ -89,12 +89,6 @@ public struct Heap<T> {
8989
return nodes.first
9090
}
9191

92-
/** Returns the node at given index */
93-
public func node(at i: Int) -> T? {
94-
guard i < nodes.count else { return nil }
95-
return nodes[i]
96-
}
97-
9892
/**
9993
* Adds a new value to the heap. This reorders the heap so that the max-heap
10094
* or min-heap property still holds. Performance: O(log n).
@@ -121,7 +115,7 @@ public struct Heap<T> {
121115
public mutating func replace(index i: Int, value: T) {
122116
guard i < nodes.count else { return }
123117

124-
removeAt(i)
118+
remove(at: i)
125119
insert(value)
126120
}
127121

@@ -130,26 +124,25 @@ public struct Heap<T> {
130124
* value; for a min-heap it is the minimum value. Performance: O(log n).
131125
*/
132126
@discardableResult public mutating func remove() -> T? {
133-
if !nodes.isEmpty {
134-
if nodes.count == 1 {
135-
return nodes.removeLast()
136-
} else {
137-
// Use the last node to replace the first one, then fix the heap by
138-
// shifting this new first node into its proper position.
139-
let value = nodes[0]
140-
nodes[0] = nodes.removeLast()
141-
shiftDown(0)
142-
return value
143-
}
127+
guard !nodes.isEmpty else { return nil }
128+
129+
if nodes.count == 1 {
130+
return nodes.removeLast()
131+
} else {
132+
// Use the last node to replace the first one, then fix the heap by
133+
// shifting this new first node into its proper position.
134+
let value = nodes[0]
135+
nodes[0] = nodes.removeLast()
136+
shiftDown(0)
137+
return value
144138
}
145-
return nil
146139
}
147140

148141
/**
149142
* Removes an arbitrary node from the heap. Performance: O(log n).
150143
* Note that you need to know the node's index.
151144
*/
152-
@discardableResult public mutating func removeAt(_ index: Int) -> T? {
145+
@discardableResult public mutating func remove(at index: Int) -> T? {
153146
guard index < nodes.count else { return nil }
154147

155148
let size = nodes.count - 1
@@ -165,7 +158,7 @@ public struct Heap<T> {
165158
* Takes a child node and looks at its parents; if a parent is not larger
166159
* (max-heap) or not smaller (min-heap) than the child, we exchange them.
167160
*/
168-
mutating func shiftUp(_ index: Int) {
161+
internal mutating func shiftUp(_ index: Int) {
169162
var childIndex = index
170163
let child = nodes[childIndex]
171164
var parentIndex = self.parentIndex(ofIndex: childIndex)
@@ -183,7 +176,7 @@ public struct Heap<T> {
183176
* Looks at a parent node and makes sure it is still larger (max-heap) or
184177
* smaller (min-heap) than its childeren.
185178
*/
186-
private mutating func shiftDown(from index: Int, until endIndex: Int) {
179+
internal mutating func shiftDown(from index: Int, until endIndex: Int) {
187180
let leftChildIndex = self.leftChildIndex(ofIndex: index)
188181
let rightChildIndex = leftChildIndex + 1
189182

@@ -204,7 +197,7 @@ public struct Heap<T> {
204197
shiftDown(from: first, until: endIndex)
205198
}
206199

207-
private mutating func shiftDown(_ index: Int) {
200+
internal mutating func shiftDown(_ index: Int) {
208201
shiftDown(from: index, until: nodes.count)
209202
}
210203

@@ -222,7 +215,7 @@ extension Heap where T: Equatable {
222215
/** Removes the first occurrence of a node from the heap. Performance: O(n log n). */
223216
@discardableResult public mutating func remove(node: T) -> T? {
224217
if let index = index(of: node) {
225-
return removeAt(index)
218+
return remove(at: index)
226219
}
227220
return nil
228221
}

Diff for: Heap/Tests/HeapTests.swift

+10-29
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,14 @@ class HeapTests: XCTestCase {
154154
XCTAssertEqual(h4.peek()!, 0)
155155
}
156156

157-
func testCreateMaxHeapEqualElements() {
157+
func testCreateMaxHeapEqualnodes() {
158158
let heap = Heap(array: [1, 1, 1, 1, 1], sort: >)
159159
XCTAssertTrue(verifyMaxHeap(heap))
160160
XCTAssertTrue(verifyMinHeap(heap))
161161
XCTAssertEqual(heap.nodes, [1, 1, 1, 1, 1])
162162
}
163163

164-
func testCreateMinHeapEqualElements() {
164+
func testCreateMinHeapEqualnodes() {
165165
let heap = Heap(array: [1, 1, 1, 1, 1], sort: <)
166166
XCTAssertTrue(verifyMinHeap(heap))
167167
XCTAssertTrue(verifyMaxHeap(heap))
@@ -198,33 +198,33 @@ class HeapTests: XCTestCase {
198198
}
199199
}
200200

201-
func testRemovingAtIndex() {
201+
func testRemoving() {
202202
var h = Heap(array: [100, 50, 70, 10, 20, 60, 65], sort: >)
203203
XCTAssertTrue(verifyMaxHeap(h))
204204
XCTAssertEqual(h.nodes, [100, 50, 70, 10, 20, 60, 65])
205205

206206
//test index out of bounds
207-
let v = h.removeAt(10)
207+
let v = h.remove(at: 10)
208208
XCTAssertEqual(v, nil)
209209
XCTAssertTrue(verifyMaxHeap(h))
210210
XCTAssertEqual(h.nodes, [100, 50, 70, 10, 20, 60, 65])
211211

212-
let v1 = h.removeAt(5)
212+
let v1 = h.remove(at: 5)
213213
XCTAssertEqual(v1, 60)
214214
XCTAssertTrue(verifyMaxHeap(h))
215215
XCTAssertEqual(h.nodes, [100, 50, 70, 10, 20, 65])
216216

217-
let v2 = h.removeAt(4)
217+
let v2 = h.remove(at: 4)
218218
XCTAssertEqual(v2, 20)
219219
XCTAssertTrue(verifyMaxHeap(h))
220220
XCTAssertEqual(h.nodes, [100, 65, 70, 10, 50])
221221

222-
let v3 = h.removeAt(4)
222+
let v3 = h.remove(at: 4)
223223
XCTAssertEqual(v3, 50)
224224
XCTAssertTrue(verifyMaxHeap(h))
225225
XCTAssertEqual(h.nodes, [100, 65, 70, 10])
226226

227-
let v4 = h.removeAt(0)
227+
let v4 = h.remove(at: 0)
228228
XCTAssertEqual(v4, 100)
229229
XCTAssertTrue(verifyMaxHeap(h))
230230
XCTAssertEqual(h.nodes, [70, 65, 10])
@@ -267,17 +267,6 @@ class HeapTests: XCTestCase {
267267
XCTAssertEqual(h.nodes, [13, 12, 9, 5, 6, 8, 7, 4, 0, 1, 2])
268268
}
269269

270-
func testRemoveNode() {
271-
var h = Heap(array: [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1], sort: >)
272-
XCTAssertTrue(verifyMaxHeap(h))
273-
XCTAssertEqual(h.nodes, [15, 13, 9, 5, 12, 8, 7, 4, 0, 6, 2, 1])
274-
XCTAssertEqual(h.node(at: 3)!, 5)
275-
let v = h.remove(node: 5)
276-
XCTAssertEqual(v, 5)
277-
XCTAssertTrue(verifyMaxHeap(h))
278-
XCTAssertFalse(h.nodes.contains(5))
279-
}
280-
281270
func testRemoveRandomItems() {
282271
for n in 1...40 {
283272
var a = randomArray(n)
@@ -288,16 +277,8 @@ class HeapTests: XCTestCase {
288277
let m = (n + 1)/2
289278
for k in 1...m {
290279
let i = Int(arc4random_uniform(UInt32(n - k + 1)))
291-
292-
var v: Int? = nil
293-
if k == 2 || k == m {
294-
v = h.remove(node: h.node(at: i)!)
295-
} else {
296-
v = h.removeAt(i)
297-
}
298-
XCTAssertNotNil(v)
299-
300-
let j = a.index(of: v!)!
280+
let v = h.remove(at: i)!
281+
let j = a.index(of: v)!
301282
a.remove(at: j)
302283

303284
XCTAssertTrue(verifyMaxHeap(h))

0 commit comments

Comments
 (0)