Skip to content

Commit 5e1975e

Browse files
authored
Merge pull request #2 from jVirus/sort/shell-core_implementation
Implemented Heap data structure
2 parents 3253d60 + b74314e commit 5e1975e

File tree

2 files changed

+243
-0
lines changed

2 files changed

+243
-0
lines changed
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
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)

Data Structures.playground/contents.xcplayground

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@
88
<page name='Linked List'/>
99
<page name='Tree'/>
1010
<page name='Graph'/>
11+
<page name='Heap'/>
1112
</pages>
1213
</playground>

0 commit comments

Comments
 (0)