Skip to content

Commit bd41e13

Browse files
committed
impl skip list
1 parent 9392777 commit bd41e13

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package ch17_skip_list
2+
3+
import scala.util.Random
4+
5+
class Node(var data: Int, var forwards: Array[Node], var maxLevel: Int)
6+
7+
class SkipList(var head: Node, var skipListLevel: Int) {
8+
9+
def this() = this(new Node(-1, new Array[Node](16), 0), 1)
10+
11+
val MAX_LEVEL = 16
12+
val random = new Random()
13+
14+
def find(value: Int): Option[Node] = {
15+
var p = head
16+
for (i <- skipListLevel - 1 to 0 by -1) {
17+
while (p.forwards(i) != null && p.forwards(i).data < value) {
18+
p = p.forwards(i)
19+
}
20+
}
21+
if (p.forwards(0) != null && p.forwards(0).data == value) {
22+
Some(p.forwards(0))
23+
} else {
24+
None
25+
}
26+
}
27+
28+
def insert(value: Int): Unit = {
29+
//init the new node
30+
val level = randomLevel()
31+
val newNode = new Node(value, new Array[Node](level), level)
32+
33+
//use updtes array to record all nodes in all level before the inserted node
34+
val updates: Array[Node] = new Array[Node](level)
35+
var p = head
36+
for (i <- level - 1 to 0 by -1) {
37+
while (p.forwards(i) != null && p.forwards(i).data < value) {
38+
p = p.forwards(i)
39+
}
40+
updates(i) = p
41+
}
42+
43+
for (i <- Range(0, level)) {
44+
newNode.forwards(i) = updates(i).forwards(i)
45+
updates(i).forwards(i) = newNode
46+
}
47+
48+
if (level > skipListLevel) {
49+
skipListLevel = level
50+
}
51+
}
52+
53+
def delete(value: Int): Unit = {
54+
var p = head
55+
val updates: Array[Node] = new Array[Node](skipListLevel)
56+
57+
//try to locate the given node with the value
58+
for (i <- skipListLevel - 1 to 0 by -1) {
59+
while (p.forwards(i) != null && p.forwards(i).data < value) {
60+
p = p.forwards(i)
61+
}
62+
updates(i) = p
63+
}
64+
65+
if (p.forwards(0) != null && p.forwards(0).data == value) {
66+
//find the value node, start to delete the node from the skip list
67+
for (i <- skipListLevel - 1 to 0 by -1) {
68+
if (updates(i).forwards(i) != null && updates(i).forwards(i).data == value) {
69+
updates(i).forwards(i) = updates(i).forwards(i).forwards(i)
70+
}
71+
}
72+
}
73+
74+
}
75+
76+
def randomLevel(): Int = {
77+
var level = 1
78+
for (i <- Range(1, MAX_LEVEL)) {
79+
if (random.nextInt() % 2 == 1) {
80+
level += 1
81+
}
82+
}
83+
84+
level
85+
}
86+
87+
def mkString(): String = {
88+
val builder = new StringBuilder
89+
var p = head
90+
while (p.forwards(0) != null) {
91+
p = p.forwards(0)
92+
builder.append(p.data)
93+
}
94+
95+
builder.mkString
96+
}
97+
}
98+
99+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package ch17_skip_list
2+
3+
import org.scalatest.{FlatSpec, Matchers}
4+
5+
import scala.util.Random
6+
7+
class SkipListTest extends FlatSpec with Matchers {
8+
9+
behavior of "SkipListTest"
10+
11+
it should "insert skip list" in {
12+
val list = new SkipList()
13+
for (i <- Range(0, 10)) {
14+
list.insert(i)
15+
}
16+
17+
list.mkString() should equal("0123456789")
18+
}
19+
20+
it should "delete skip list" in {
21+
val list = new SkipList()
22+
for (i <- Range(0, 10)) {
23+
list.insert(i)
24+
}
25+
26+
list.delete(5)
27+
list.mkString() should equal("012346789")
28+
}
29+
30+
it should "find value in skip list" in {
31+
val list = new SkipList()
32+
val length = 5000
33+
val array = new Array[Int](length)
34+
val rnd = new Random()
35+
for (i <- Range(0, length)) {
36+
array(i) = rnd.nextInt(length)
37+
list.insert(array(i))
38+
}
39+
40+
assert(list.find(array(rnd.nextInt(length - 1))).isDefined)
41+
assert(list.find(array(rnd.nextInt(length - 1)) + length + 1).isEmpty)
42+
43+
}
44+
}

0 commit comments

Comments
 (0)