-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathHeap.swift
More file actions
164 lines (129 loc) · 3.93 KB
/
Heap.swift
File metadata and controls
164 lines (129 loc) · 3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//
// Heap.swift
// Testor
//
// Created by woong on 2020/10/18.
// Copyright © 2020 woong. All rights reserved.
//
import Foundation
/*
peek: O(1)
insert/delete: O(logN)
*/
protocol Heapable {
associatedtype T
var isEmpty: Bool { get }
var count: Int { get }
func peek() -> T?
mutating func insert(_ value: T)
mutating func remove() -> T?
mutating func remove(at index: Int) -> T?
}
struct Heap<T>: Heapable {
typealias T = T
var nodes = [T]()
private var orderCriteria: (T, T) -> Bool
init(sort: @escaping (T, T) -> Bool) {
self.orderCriteria = sort
}
init(array: [T], sort: @escaping (T, T) -> Bool) {
self.orderCriteria = sort
configureHeap(from: array)
}
private mutating func configureHeap(from array: [T]) {
nodes = array
for i in stride(from: (nodes.count/2-1), through: 0, by: -1) {
shiftDown(i)
}
}
var isEmpty: Bool {
return nodes.isEmpty
}
var count: Int {
return nodes.count
}
func peek() -> T? {
return nodes.first
}
mutating func replace(index i: Int, value: T) {
guard 0..<nodes.count ~= i else { return }
remove(at: i)
insert(value)
}
mutating func insert(_ value: T) {
nodes.append(value)
shiftUp(nodes.count-1)
}
@discardableResult
mutating func remove() -> T? {
guard !nodes.isEmpty else { return nil }
if nodes.count == 1 {
return nodes.removeLast()
} else {
let value = nodes[0]
nodes[0] = nodes.removeLast()
shiftDown(0)
return value
}
}
@discardableResult
mutating func remove(at index: Int) -> T? {
guard 0..<nodes.count ~= index else { return nil }
let end = nodes.count-1
if index != end {
nodes.swapAt(index, end)
shiftDown(index)
shiftUp(index)
}
return nodes.removeLast()
}
// MARK: Private
private func parentIndex(of index: Int) -> Int {
return (index-1) / 2
}
private func leftChildIndex(of index: Int) -> Int {
return index*2 + 1
}
private func rightChildIndex(of index: Int) -> Int {
return index*2 + 2
}
private mutating func shiftUp(_ index: Int) {
var childIndex = index
let child = nodes[childIndex]
var parentIndex = self.parentIndex(of: index)
while childIndex > 0, orderCriteria(child, nodes[parentIndex]) {
nodes[childIndex] = nodes[parentIndex]
childIndex = parentIndex
parentIndex = self.parentIndex(of: childIndex)
}
nodes[childIndex] = child
}
private mutating func shiftDown(from index: Int, until endIndex: Int) {
let leftChildIndex = self.leftChildIndex(of: index)
let rightChildIndex = self.rightChildIndex(of: index)
var first = index
if leftChildIndex < endIndex, orderCriteria(nodes[first], nodes[leftChildIndex]) {
first = leftChildIndex
}
if rightChildIndex < endIndex, orderCriteria(nodes[first], nodes[rightChildIndex]) {
first = rightChildIndex
}
guard first != index else { return }
nodes.swapAt(first, index)
shiftDown(from: first, until: endIndex)
}
private mutating func shiftDown(_ index: Int) {
shiftDown(from: index, until: nodes.endIndex)
}
}
// MARK: - Searching
extension Heap where T: Equatable {
func index(of node: T) -> Int? {
return nodes.firstIndex(of: node)
}
@discardableResult
mutating func remove(node: T) -> T? {
guard let index = nodes.firstIndex(of: node) else { return nil }
return nodes.remove(at: index)
}
}