|
| 1 | +// |
| 2 | +// Heap.swift |
| 3 | +// Written for the Swift Algorithm Club by Kevin Randrup and Matthijs Hollemans |
| 4 | +// |
| 5 | + |
| 6 | +public struct Heap<T> { |
| 7 | + /** The array that stores the heap's nodes. */ |
| 8 | + var elements = [T]() |
| 9 | + |
| 10 | + /** Determines whether this is a max-heap (>) or min-heap (<). */ |
| 11 | + private var isOrderedBefore: (T, T) -> Bool |
| 12 | + |
| 13 | + /** |
| 14 | + * Creates an empty heap. |
| 15 | + * The sort function determines whether this is a min-heap or max-heap. |
| 16 | + * For integers, > makes a max-heap, < makes a min-heap. |
| 17 | + */ |
| 18 | + public init(sort: (T, T) -> Bool) { |
| 19 | + self.isOrderedBefore = sort |
| 20 | + } |
| 21 | + |
| 22 | + /** |
| 23 | + * Creates a heap from an array. The order of the array does not matter; |
| 24 | + * the elements are inserted into the heap in the order determined by the |
| 25 | + * sort function. |
| 26 | + */ |
| 27 | + public init(array: [T], sort: (T, T) -> Bool) { |
| 28 | + self.isOrderedBefore = sort |
| 29 | + buildHeap(array) |
| 30 | + } |
| 31 | + |
| 32 | + /* |
| 33 | + // This version has O(n log n) performance. |
| 34 | + private mutating func buildHeap(array: [T]) { |
| 35 | + elements.reserveCapacity(array.count) |
| 36 | + for value in array { |
| 37 | + insert(value) |
| 38 | + } |
| 39 | + } |
| 40 | + */ |
| 41 | + |
| 42 | + /** |
| 43 | + * Converts an array to a max-heap or min-heap in a bottom-up manner. |
| 44 | + * Performance: This runs pretty much in O(n). |
| 45 | + */ |
| 46 | + private mutating func buildHeap(array: [T]) { |
| 47 | + elements = array |
| 48 | + for i in (elements.count/2 - 1).stride(through: 0, by: -1) { |
| 49 | + shiftDown(index: i, heapSize: elements.count) |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | + public var isEmpty: Bool { |
| 54 | + return elements.isEmpty |
| 55 | + } |
| 56 | + |
| 57 | + public var count: Int { |
| 58 | + return elements.count |
| 59 | + } |
| 60 | + |
| 61 | + /** |
| 62 | + * Returns the index of the parent of the element at index i. |
| 63 | + * The element at index 0 is the root of the tree and has no parent. |
| 64 | + */ |
| 65 | + @inline(__always) func indexOfParent(i: Int) -> Int { |
| 66 | + return (i - 1) / 2 |
| 67 | + } |
| 68 | + |
| 69 | + /** |
| 70 | + * Returns the index of the left child of the element at index i. |
| 71 | + * Note that this index can be greater than the heap size, in which case |
| 72 | + * there is no left child. |
| 73 | + */ |
| 74 | + @inline(__always) func indexOfLeftChild(i: Int) -> Int { |
| 75 | + return 2*i + 1 |
| 76 | + } |
| 77 | + |
| 78 | + /** |
| 79 | + * Returns the index of the right child of the element at index i. |
| 80 | + * Note that this index can be greater than the heap size, in which case |
| 81 | + * there is no right child. |
| 82 | + */ |
| 83 | + @inline(__always) func indexOfRightChild(i: Int) -> Int { |
| 84 | + return 2*i + 2 |
| 85 | + } |
| 86 | + |
| 87 | + /** |
| 88 | + * Returns the maximum value in the heap (for a max-heap) or the minimum |
| 89 | + * value (for a min-heap). |
| 90 | + */ |
| 91 | + public func peek() -> T? { |
| 92 | + return elements.first |
| 93 | + } |
| 94 | + |
| 95 | + /** |
| 96 | + * Adds a new value to the heap. This reorders the heap so that the max-heap |
| 97 | + * or min-heap property still holds. Performance: O(log n). |
| 98 | + */ |
| 99 | + public mutating func insert(value: T) { |
| 100 | + elements.append(value) |
| 101 | + shiftUp(index: elements.count - 1) |
| 102 | + } |
| 103 | + |
| 104 | + public mutating func insert<S : SequenceType where S.Generator.Element == T>(sequence: S) { |
| 105 | + for value in sequence { |
| 106 | + insert(value) |
| 107 | + } |
| 108 | + } |
| 109 | + |
| 110 | + /** |
| 111 | + * Allows you to change an element. In a max-heap, the new element should be |
| 112 | + * larger than the old one; in a min-heap it should be smaller. |
| 113 | + */ |
| 114 | + public mutating func replace(index i: Int, value: T) { |
| 115 | + assert(isOrderedBefore(value, elements[i])) |
| 116 | + elements[i] = value |
| 117 | + shiftUp(index: i) |
| 118 | + } |
| 119 | + |
| 120 | + /** |
| 121 | + * Removes the root node from the heap. For a max-heap, this is the maximum |
| 122 | + * value; for a min-heap it is the minimum value. Performance: O(log n). |
| 123 | + */ |
| 124 | + public mutating func remove() -> T? { |
| 125 | + if elements.isEmpty { |
| 126 | + return nil |
| 127 | + } else if elements.count == 1 { |
| 128 | + return elements.removeLast() |
| 129 | + } else { |
| 130 | + // Use the last node to replace the first one, then fix the heap by |
| 131 | + // shifting this new first node into its proper position. |
| 132 | + let value = elements[0] |
| 133 | + elements[0] = elements.removeLast() |
| 134 | + shiftDown() |
| 135 | + return value |
| 136 | + } |
| 137 | + } |
| 138 | + |
| 139 | + /** |
| 140 | + * Removes an arbitrary node from the heap. Performance: O(log n). You need |
| 141 | + * to know the node's index, which may actually take O(n) steps to find. |
| 142 | + */ |
| 143 | + public mutating func removeAtIndex(i: Int) -> T? { |
| 144 | + let size = elements.count - 1 |
| 145 | + if i != size { |
| 146 | + swap(&elements[i], &elements[size]) |
| 147 | + shiftDown(index: i, heapSize: size) |
| 148 | + shiftUp(index: i) |
| 149 | + } |
| 150 | + return elements.removeLast() |
| 151 | + } |
| 152 | + |
| 153 | + /** |
| 154 | + * Takes a child node and looks at its parents; if a parent is not larger |
| 155 | + * (max-heap) or not smaller (min-heap) than the child, we exchange them. |
| 156 | + */ |
| 157 | + mutating func shiftUp(index index: Int) { |
| 158 | + var childIndex = index |
| 159 | + let child = elements[childIndex] |
| 160 | + var parentIndex = indexOfParent(childIndex) |
| 161 | + |
| 162 | + while childIndex > 0 && isOrderedBefore(child, elements[parentIndex]) { |
| 163 | + elements[childIndex] = elements[parentIndex] |
| 164 | + childIndex = parentIndex |
| 165 | + parentIndex = indexOfParent(childIndex) |
| 166 | + } |
| 167 | + |
| 168 | + elements[childIndex] = child |
| 169 | + } |
| 170 | + |
| 171 | + mutating func shiftDown() { |
| 172 | + shiftDown(index: 0, heapSize: elements.count) |
| 173 | + } |
| 174 | + |
| 175 | + /** |
| 176 | + * Looks at a parent node and makes sure it is still larger (max-heap) or |
| 177 | + * smaller (min-heap) than its childeren. |
| 178 | + */ |
| 179 | + mutating func shiftDown(index index: Int, heapSize: Int) { |
| 180 | + var parentIndex = index |
| 181 | + |
| 182 | + while true { |
| 183 | + let leftChildIndex = indexOfLeftChild(parentIndex) |
| 184 | + let rightChildIndex = leftChildIndex + 1 |
| 185 | + |
| 186 | + // Figure out which comes first if we order them by the sort function: |
| 187 | + // the parent, the left child, or the right child. If the parent comes |
| 188 | + // first, we're done. If not, that element is out-of-place and we make |
| 189 | + // it "float down" the tree until the heap property is restored. |
| 190 | + var first = parentIndex |
| 191 | + if leftChildIndex < heapSize && isOrderedBefore(elements[leftChildIndex], elements[first]) { |
| 192 | + first = leftChildIndex |
| 193 | + } |
| 194 | + if rightChildIndex < heapSize && isOrderedBefore(elements[rightChildIndex], elements[first]) { |
| 195 | + first = rightChildIndex |
| 196 | + } |
| 197 | + if first == parentIndex { return } |
| 198 | + |
| 199 | + swap(&elements[parentIndex], &elements[first]) |
| 200 | + parentIndex = first |
| 201 | + } |
| 202 | + } |
| 203 | +} |
| 204 | + |
| 205 | +// MARK: - Searching |
| 206 | + |
| 207 | +extension Heap where T: Equatable { |
| 208 | + /** |
| 209 | + * Searches the heap for the given element. Performance: O(n). |
| 210 | + */ |
| 211 | + public func indexOf(element: T) -> Int? { |
| 212 | + return indexOf(element, 0) |
| 213 | + } |
| 214 | + |
| 215 | + private func indexOf(element: T, _ i: Int) -> Int? { |
| 216 | + if i >= count { return nil } |
| 217 | + if isOrderedBefore(element, elements[i]) { return nil } |
| 218 | + if element == elements[i] { return i } |
| 219 | + if let j = indexOf(element, indexOfLeftChild(i)) { return j } |
| 220 | + if let j = indexOf(element, indexOfRightChild(i)) { return j } |
| 221 | + return nil |
| 222 | + } |
| 223 | +} |
0 commit comments