Skip to content

Commit ef52311

Browse files
committed
[Swift 4] Update Skip List
1 parent 61c9376 commit ef52311

File tree

6 files changed

+295
-9
lines changed

6 files changed

+295
-9
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// last checked with Xcode 9.0b4
2+
#if swift(>=4.0)
3+
print("Hello, Swift 4!")
4+
#endif
5+
6+
// SkipList is ready for Swift 4.
7+
// TODO: Add Test
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
// The MIT License (MIT)
2+
3+
// Copyright (c) 2016 Mike Taghavi (mitghi[at]me.com)
4+
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
12+
// The above copyright notice and this permission notice shall be included in all
13+
// copies or substantial portions of the Software.
14+
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
import Foundation
24+
25+
// Stack from : https://github.com/raywenderlich/swift-algorithm-club/tree/master/Stack
26+
public struct Stack<T> {
27+
fileprivate var array: [T] = []
28+
29+
public var isEmpty: Bool {
30+
return array.isEmpty
31+
}
32+
33+
public var count: Int {
34+
return array.count
35+
}
36+
37+
public mutating func push(_ element: T) {
38+
array.append(element)
39+
}
40+
41+
public mutating func pop() -> T? {
42+
return array.popLast()
43+
}
44+
45+
public func peek() -> T? {
46+
return array.last
47+
}
48+
}
49+
50+
extension Stack: Sequence {
51+
public func makeIterator() -> AnyIterator<T> {
52+
var curr = self
53+
return AnyIterator { curr.pop() }
54+
}
55+
}
56+
57+
private func coinFlip() -> Bool {
58+
return arc4random_uniform(2) == 1
59+
}
60+
61+
public class DataNode<Key: Comparable, Payload> {
62+
public typealias Node = DataNode<Key, Payload>
63+
64+
var data: Payload?
65+
fileprivate var key: Key?
66+
var next: Node?
67+
var down: Node?
68+
69+
public init(key: Key, data: Payload) {
70+
self.key = key
71+
self.data = data
72+
}
73+
74+
public init(asHead head: Bool) {}
75+
76+
}
77+
78+
open class SkipList<Key: Comparable, Payload> {
79+
public typealias Node = DataNode<Key, Payload>
80+
81+
fileprivate(set) var head: Node?
82+
83+
public init() {}
84+
85+
}
86+
87+
// MARK: - Search lanes for a node with a given key
88+
89+
extension SkipList {
90+
91+
func findNode(key: Key) -> Node? {
92+
var currentNode: Node? = head
93+
var isFound: Bool = false
94+
95+
while !isFound {
96+
if let node = currentNode {
97+
98+
switch node.next {
99+
case .none:
100+
101+
currentNode = node.down
102+
case .some(let value) where value.key != nil:
103+
104+
if value.key == key {
105+
isFound = true
106+
break
107+
} else {
108+
if key < value.key! {
109+
currentNode = node.down
110+
} else {
111+
currentNode = node.next
112+
}
113+
}
114+
115+
default:
116+
continue
117+
}
118+
119+
} else {
120+
break
121+
}
122+
}
123+
124+
if isFound {
125+
return currentNode
126+
} else {
127+
return nil
128+
}
129+
130+
}
131+
132+
func search(key: Key) -> Payload? {
133+
guard let node = findNode(key: key) else {
134+
return nil
135+
}
136+
137+
return node.next!.data
138+
}
139+
140+
}
141+
142+
// MARK: - Insert a node into lanes depending on skip list status ( bootstrap base-layer if head is empty / start insertion from current head ).
143+
144+
extension SkipList {
145+
private func bootstrapBaseLayer(key: Key, data: Payload) {
146+
head = Node(asHead: true)
147+
var node = Node(key: key, data: data)
148+
149+
head!.next = node
150+
151+
var currentTopNode = node
152+
153+
while coinFlip() {
154+
let newHead = Node(asHead: true)
155+
node = Node(key: key, data: data)
156+
node.down = currentTopNode
157+
newHead.next = node
158+
newHead.down = head
159+
head = newHead
160+
currentTopNode = node
161+
}
162+
163+
}
164+
165+
private func insertItem(key: Key, data: Payload) {
166+
var stack = Stack<Node>()
167+
var currentNode: Node? = head
168+
169+
while currentNode != nil {
170+
171+
if let nextNode = currentNode!.next {
172+
if nextNode.key! > key {
173+
stack.push(currentNode!)
174+
currentNode = currentNode!.down
175+
} else {
176+
currentNode = nextNode
177+
}
178+
179+
} else {
180+
stack.push(currentNode!)
181+
currentNode = currentNode!.down
182+
}
183+
184+
}
185+
186+
let itemAtLayer = stack.pop()
187+
var node = Node(key: key, data: data)
188+
node.next = itemAtLayer!.next
189+
itemAtLayer!.next = node
190+
var currentTopNode = node
191+
192+
while coinFlip() {
193+
if stack.isEmpty {
194+
let newHead = Node(asHead: true)
195+
196+
node = Node(key: key, data: data)
197+
node.down = currentTopNode
198+
newHead.next = node
199+
newHead.down = head
200+
head = newHead
201+
currentTopNode = node
202+
203+
} else {
204+
let nextNode = stack.pop()
205+
206+
node = Node(key: key, data: data)
207+
node.down = currentTopNode
208+
node.next = nextNode!.next
209+
nextNode!.next = node
210+
currentTopNode = node
211+
}
212+
}
213+
}
214+
215+
func insert(key: Key, data: Payload) {
216+
if head != nil {
217+
if let node = findNode(key: key) {
218+
// replace, in case of key already exists.
219+
var currentNode = node.next
220+
while currentNode != nil && currentNode!.key == key {
221+
currentNode!.data = data
222+
currentNode = currentNode!.down
223+
}
224+
} else {
225+
insertItem(key: key, data: data)
226+
}
227+
228+
} else {
229+
bootstrapBaseLayer(key: key, data: data)
230+
}
231+
}
232+
233+
}
234+
235+
// MARK: - Remove a node with a given key. First, find its position in layers at the top, then remove it from each lane by traversing down to the base layer.
236+
237+
extension SkipList {
238+
public func remove(key: Key) {
239+
guard let item = findNode(key: key) else {
240+
return
241+
}
242+
243+
var currentNode = Optional(item)
244+
245+
while currentNode != nil {
246+
let node = currentNode!.next
247+
248+
if node!.key != key {
249+
currentNode = node
250+
continue
251+
}
252+
253+
let nextNode = node!.next
254+
255+
currentNode!.next = nextNode
256+
currentNode = currentNode!.down
257+
258+
}
259+
260+
}
261+
}
262+
263+
// MARK: - Get associated payload from a node with a given key.
264+
265+
extension SkipList {
266+
267+
public func get(key: Key) -> Payload? {
268+
return search(key: key)
269+
}
270+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<playground version='5.0' target-platform='ios'>
3+
<timeline fileName='timeline.xctimeline'/>
4+
</playground>

Skip-List/SkipList.playground/playground.xcworkspace/contents.xcworkspacedata

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Skip-List/SkipList.swift

+4-9
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,12 @@ public struct Stack<T> {
5050
extension Stack: Sequence {
5151
public func makeIterator() -> AnyIterator<T> {
5252
var curr = self
53-
return AnyIterator { _ -> T? in
54-
return curr.pop()
55-
}
53+
return AnyIterator { curr.pop() }
5654
}
5755
}
5856

5957
private func coinFlip() -> Bool {
60-
#if os(Linux)
61-
return random() % 2 == 0
62-
#elseif os(OSX)
63-
return arc4random_uniform(2) == 1
64-
#endif
58+
return arc4random_uniform(2) == 1
6559
}
6660

6761
public class DataNode<Key: Comparable, Payload> {
@@ -221,7 +215,7 @@ extension SkipList {
221215
func insert(key: Key, data: Payload) {
222216
if head != nil {
223217
if let node = findNode(key: key) {
224-
// replace, in case of key already exists.
218+
// replace, in case of key already exists.
225219
var currentNode = node.next
226220
while currentNode != nil && currentNode!.key == key {
227221
currentNode!.data = data
@@ -274,3 +268,4 @@ extension SkipList {
274268
return search(key: key)
275269
}
276270
}
271+

swift-algorithm-club.xcworkspace/contents.xcworkspacedata

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)