|
| 1 | +//: [Previous](@previous) |
| 2 | + |
| 3 | +import Foundation |
| 4 | + |
| 5 | +public struct Heap<T> where T: Comparable, T: CustomStringConvertible { |
| 6 | + |
| 7 | + // MARK: - Constants |
| 8 | + |
| 9 | + private let zero = 0 |
| 10 | + |
| 11 | + // MARK: - Properties |
| 12 | + |
| 13 | + var nodes = [T]() |
| 14 | + |
| 15 | + public var isEmpty: Bool { |
| 16 | + return nodes.isEmpty |
| 17 | + } |
| 18 | + |
| 19 | + public var count: Int { |
| 20 | + return nodes.count |
| 21 | + } |
| 22 | + |
| 23 | + // MARK: - Private properties |
| 24 | + |
| 25 | + fileprivate var order: (T, T) -> Bool |
| 26 | + |
| 27 | + // MARK: - Initializers |
| 28 | + |
| 29 | + public init(order: @escaping (T, T) -> Bool) { |
| 30 | + self.order = order |
| 31 | + } |
| 32 | + |
| 33 | + public init(array: [T], order: @escaping (T, T) -> Bool) { |
| 34 | + self.order = order |
| 35 | + setup(using: array) |
| 36 | + } |
| 37 | + |
| 38 | + // MARK: - Methods |
| 39 | + |
| 40 | + public func peek() -> T? { |
| 41 | + return nodes.first |
| 42 | + } |
| 43 | + |
| 44 | + public mutating func insert(node: T) { |
| 45 | + nodes.append(node) |
| 46 | + shiftUp(count - 1) |
| 47 | + } |
| 48 | + |
| 49 | + public mutating func insert<S: Sequence>(_ sequence: S) where S.Iterator.Element == T { |
| 50 | + sequence.forEach { element in |
| 51 | + insert(node: element) |
| 52 | + } |
| 53 | + } |
| 54 | + |
| 55 | + public mutating func replace(elementAt index: Int, with value: T) { |
| 56 | + guard index < nodes.count else { return } |
| 57 | + remove(at: index) |
| 58 | + insert(node: value) |
| 59 | + } |
| 60 | + |
| 61 | + @discardableResult public mutating func remove() -> T? { |
| 62 | + guard !nodes.isEmpty else { return nil } |
| 63 | + |
| 64 | + switch nodes.count { |
| 65 | + case 1: |
| 66 | + return nodes.removeLast() |
| 67 | + default: |
| 68 | + let value = nodes[zero] |
| 69 | + nodes[zero] = nodes.removeLast() |
| 70 | + shiftDown(zero) |
| 71 | + return value |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + @discardableResult public mutating func remove(at index: Int) -> T? { |
| 76 | + guard index < nodes.count else { return nil } |
| 77 | + let size = count - 1 |
| 78 | + |
| 79 | + if index != size { |
| 80 | + nodes.swapAt(index, size) |
| 81 | + shiftDown(from: index, until: size) |
| 82 | + shiftUp(index) |
| 83 | + } |
| 84 | + return nodes.removeLast() |
| 85 | + } |
| 86 | + |
| 87 | + // MARK: - Shifting |
| 88 | + |
| 89 | + internal mutating func shiftDown(from startIndex: Int, until endIndex: Int) { |
| 90 | + let leftChildIndex = self.leftChildIndex(of: startIndex) |
| 91 | + let rightChildIndex = leftChildIndex + 1 |
| 92 | + var first = startIndex |
| 93 | + |
| 94 | + if leftChildIndex < endIndex && order(nodes[leftChildIndex], nodes[first]) { |
| 95 | + first = leftChildIndex |
| 96 | + } |
| 97 | + if rightChildIndex < endIndex && order(nodes[rightChildIndex], nodes[first]) { |
| 98 | + first = rightChildIndex |
| 99 | + } |
| 100 | + if first == startIndex { return } |
| 101 | + |
| 102 | + nodes.swapAt(startIndex, first) |
| 103 | + shiftDown(from: first, until: endIndex) |
| 104 | + } |
| 105 | + |
| 106 | + internal mutating func shiftDown(_ index: Int) { |
| 107 | + shiftDown(from: index, until: count) |
| 108 | + } |
| 109 | + |
| 110 | + internal mutating func shiftUp(_ index: Int) { |
| 111 | + var childIndex = index |
| 112 | + let child = nodes[childIndex] |
| 113 | + var parentIndex = self.parentIndex(of: childIndex) |
| 114 | + |
| 115 | + while childIndex > 0 && order(child, nodes[parentIndex]) { |
| 116 | + nodes[childIndex] = nodes[parentIndex] |
| 117 | + childIndex = parentIndex |
| 118 | + parentIndex = self.parentIndex(of: childIndex) |
| 119 | + } |
| 120 | + nodes[childIndex] = child |
| 121 | + } |
| 122 | + |
| 123 | + // MARK: - Child indicies |
| 124 | + |
| 125 | + @inline(__always) internal func rightChildIndex(of index: Int) -> Int { |
| 126 | + return 2 * index + 2 |
| 127 | + } |
| 128 | + |
| 129 | + @inline(__always) internal func leftChildIndex(of index: Int) -> Int { |
| 130 | + return 2 * index + 1 |
| 131 | + } |
| 132 | + |
| 133 | + @inline(__always) internal func parentIndex(of index: Int) -> Int { |
| 134 | + return (index - 1) / 2 |
| 135 | + } |
| 136 | + |
| 137 | + // MARK: - Private helpers |
| 138 | + |
| 139 | + private mutating func setup(using nodesArray: [T]) { |
| 140 | + self.nodes = nodesArray |
| 141 | + let strideCondition = stride(from: (count / 2 - 1), through: 0, by: -1) |
| 142 | + |
| 143 | + for index in strideCondition { |
| 144 | + shiftDown(index) |
| 145 | + } |
| 146 | + } |
| 147 | + |
| 148 | +} |
| 149 | + |
| 150 | +/*: |
| 151 | + Basically we created wrapper around standard Array type. However we need to carefully take a look at the two important pieces of the implenentation: |
| 152 | + - T type which is a generic placeholder |
| 153 | + - Custom initializer that accepts iterator element of Sequence protocol - this is simply a complementary initializer that allows client-developer to pass other Stack structs, Arra or any other type that conforms to Sequnce protocol to use it at initialization phase. Convenience and compatability with standard library - nothing sophisticated. |
| 154 | + |
| 155 | + |
| 156 | + The following extension adds support for debugging capabilites for both regular "print" and "debugPrint" statements |
| 157 | + */ |
| 158 | +extension Heap: CustomStringConvertible, CustomDebugStringConvertible { |
| 159 | + |
| 160 | + // MARK: - Properties |
| 161 | + |
| 162 | + public var description: String { |
| 163 | + return nodes.description |
| 164 | + } |
| 165 | + |
| 166 | + public var debugDescription: String { |
| 167 | +// prepareDebugPrint() |
| 168 | + return nodes.debugDescription |
| 169 | + } |
| 170 | + |
| 171 | + /* |
| 172 | + func prepareDebugPrint() -> String { |
| 173 | + var innerLength = 1 |
| 174 | + var start = 0 |
| 175 | + var end = innerLength |
| 176 | + |
| 177 | + |
| 178 | + for var index in 0..<count { |
| 179 | + |
| 180 | +// Swift.print(innerLength) |
| 181 | + Swift.print("start: ", start, " end: ", end) |
| 182 | + |
| 183 | + for val in start..<end { |
| 184 | + Swift.print(val) |
| 185 | + } |
| 186 | + |
| 187 | + if innerLength == count { |
| 188 | + break |
| 189 | + } |
| 190 | + |
| 191 | + if innerLength <= 1 { |
| 192 | + innerLength += 1 |
| 193 | + } else { |
| 194 | + innerLength *= 2 |
| 195 | + } |
| 196 | + |
| 197 | + start = index + 1 |
| 198 | + end = innerLength + 1 |
| 199 | + |
| 200 | + if innerLength > count { |
| 201 | + innerLength = count |
| 202 | + } |
| 203 | + } |
| 204 | + return "" |
| 205 | + } |
| 206 | + */ |
| 207 | + |
| 208 | +} |
| 209 | + |
| 210 | +extension Heap: ExpressibleByArrayLiteral { |
| 211 | + |
| 212 | + public init(arrayLiteral elements: T...) { |
| 213 | + self.init(array: elements, order: <) |
| 214 | + } |
| 215 | +} |
| 216 | + |
| 217 | +/*: |
| 218 | + Adds support for Sequence protocol. The Swift's runtime will call the makeIterator() method to initialize the for...in loop. All we need to do is to return some soft of iterator instance that conforms to IteratorProtocol. Iterator protocol allows us to return an iterator based on the type of elements out target type contains - in this particular case it is Stack. |
| 219 | + */ |
| 220 | +extension Heap: Sequence { |
| 221 | + |
| 222 | + public func makeIterator() -> AnyIterator<T> { |
| 223 | + let idexedIterator = IndexingIterator(_elements: self.nodes.lazy.reversed()) |
| 224 | + return AnyIterator(idexedIterator) |
| 225 | + } |
| 226 | +} |
| 227 | + |
| 228 | + |
| 229 | +//: Usage |
| 230 | + |
| 231 | + |
| 232 | +var maxHeap = Heap<Int>(order: >) |
| 233 | +maxHeap.insert(node: 1) |
| 234 | +maxHeap.insert(node: 5) |
| 235 | +maxHeap.insert(node: 2) |
| 236 | +maxHeap.insert(node: 7) |
| 237 | +maxHeap.insert(node: 9) |
| 238 | + |
| 239 | +//var heap: Heap = [3, 1, 4, 2, 7, 9, 8] |
| 240 | + |
| 241 | + |
| 242 | +//: [Next](@next) |
0 commit comments