-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSkipList.swift
More file actions
executable file
·172 lines (154 loc) · 5.61 KB
/
SkipList.swift
File metadata and controls
executable file
·172 lines (154 loc) · 5.61 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
165
166
167
168
169
170
//
// Created by Daniel Heredia on 2/27/18.
// Copyright © 2018 Daniel Heredia. All rights reserved.
//
// Skip List
import Foundation
//// Vars used to debug (repeat the same random values in all runs
//let rresults: [Int] = [0,1,0,0,0,3,0,1,0,0]
//var rrindex: Int = 0
class Node<Element> where Element: Comparable{
let key: Element
var forward: [Node<Element>]
var level: Int
init(key: Element, level: Int) {
self.key = key
self.forward = [Node<Element>]()
self.level = level
}
}
class SkipList<Element> where Element: Comparable {
let maxLevel: Int
let p: Float
var level: Int
let header: Node<Element>
init(maxLevel: Int, p: Float, minimumExcludedValue excludedKey: Element) {
self.maxLevel = maxLevel
self.p = p
self.level = 0
self.header = Node(key: excludedKey, level: 0)
}
func randomLevel() -> Int {
// //Use this variables to debug with same random values in all runs
// let rlevel = rresults[rrindex]
// rrindex += 1
var rlevel = 0
var r = Float(arc4random()) / Float(UInt32.max)
while r < p && rlevel < self.maxLevel {
rlevel += 1
r = Float(arc4random()) / Float(UInt32.max)
}
//print("rl: \(rlevel)")
return rlevel
}
func createNode(key: Element, level: Int) -> Node<Element> {
return Node(key: key, level: level)
}
func insertElement(_ key: Element) {
// Find the path to the node to insert and the last node before
var (current, update) = findPathToKey(key)
// The insertion must be done if there is a free position next to the current or
// the next key is different to the key to insert
let shouldInsert = current.forward.count == 0 || current.forward[0].key != key
if shouldInsert {
let randomLevel = self.randomLevel()
let newNode = Node(key: key, level: randomLevel)
for i in 0...randomLevel {
if i >= update.count {
update.append(header)
self.header.level += 1
self.level += 1
}
if i >= update[i].forward.count {
update[i].forward.append(newNode)
} else {
newNode.forward.append(update[i].forward[i])
update[i].forward[i] = newNode
}
}
} else {
print("The key \(key) was not inserted because it already exists in the lists.")
}
}
func findKey(_ key: Element) -> Node<Element>? {
let (lastNode, _) = findPathToKey(key)
if lastNode.forward.count > 0 && lastNode.forward[0].key == key {
return lastNode.forward[0]
} else {
return nil
}
}
func deleteKey(_ key: Element) {
let (lastNode, updatePath) = findPathToKey(key)
if lastNode.forward.count > 0 && lastNode.forward[0].key == key {
// Update nodes references in the path
let deleteNode = lastNode.forward[0]
for i in 0...level {
if updatePath[i].forward.count > i && updatePath[i].forward[i] === deleteNode {
if deleteNode.forward.count > i {
updatePath[i].forward[i] = deleteNode.forward[i]
} else {
updatePath[i].forward.remove(at: i)
if updatePath[i] === self.header {
// Update the level if necessary
self.header.level -= 1
self.level -= 1
}
}
} else {
break
}
}
}
}
func printList() {
print("> Skip list")
for i in stride(from: self.level, through: 0, by: -1) {
var lineOutput = ""
lineOutput.append("Level \(i): ")
var node: Node? = self.header.forward[i]
while let cNode = node {
let stringKey = String(format: "%03d ", cNode.key as! CVarArg)
lineOutput.append(stringKey)
if cNode.forward.count <= i {
node = nil
} else {
node = cNode.forward[i]
}
}
print(lineOutput)
}
}
private func findPathToKey(_ key: Element) -> (lastNode: Node<Element>, path:[Node<Element>]) {
var currentNode = self.header
// Find every previous node involved in the insertion/search in each level
var path = [Node<Element>]()
for i in stride(from: level, through: 0, by: -1) {
while currentNode.forward.count > i &&
currentNode.forward[i].key < key {
currentNode = currentNode.forward[i]
}
path.insert(currentNode, at: 0)
}
return (currentNode, path)
}
}
let skipList = SkipList(maxLevel: 3, p: 0.5, minimumExcludedValue: Int.min)
skipList.insertElement(3)
skipList.insertElement(6)
skipList.insertElement(7)
skipList.insertElement(9)
skipList.insertElement(12)
skipList.insertElement(19)
skipList.insertElement(17)
skipList.insertElement(26)
skipList.insertElement(21)
skipList.insertElement(25)
skipList.printList()
let searchKey = 13
let searchResult = skipList.findKey(searchKey)
print("Exists key \(searchKey) in the list? \(searchResult != nil)")
let deleteKey = 12
skipList.deleteKey(deleteKey)
print("Removing key \(deleteKey)")
skipList.printList()