Skip to content

Commit

Permalink
impl skip list
Browse files Browse the repository at this point in the history
  • Loading branch information
email2liyang committed Jan 3, 2019
1 parent 9392777 commit bd41e13
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 0 deletions.
99 changes: 99 additions & 0 deletions scala/src/main/scala/ch17_skip_list/SkipList.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package ch17_skip_list

import scala.util.Random

class Node(var data: Int, var forwards: Array[Node], var maxLevel: Int)

class SkipList(var head: Node, var skipListLevel: Int) {

def this() = this(new Node(-1, new Array[Node](16), 0), 1)

val MAX_LEVEL = 16
val random = new Random()

def find(value: Int): Option[Node] = {
var p = head
for (i <- skipListLevel - 1 to 0 by -1) {
while (p.forwards(i) != null && p.forwards(i).data < value) {
p = p.forwards(i)
}
}
if (p.forwards(0) != null && p.forwards(0).data == value) {
Some(p.forwards(0))
} else {
None
}
}

def insert(value: Int): Unit = {
//init the new node
val level = randomLevel()
val newNode = new Node(value, new Array[Node](level), level)

//use updtes array to record all nodes in all level before the inserted node
val updates: Array[Node] = new Array[Node](level)
var p = head
for (i <- level - 1 to 0 by -1) {
while (p.forwards(i) != null && p.forwards(i).data < value) {
p = p.forwards(i)
}
updates(i) = p
}

for (i <- Range(0, level)) {
newNode.forwards(i) = updates(i).forwards(i)
updates(i).forwards(i) = newNode
}

if (level > skipListLevel) {
skipListLevel = level
}
}

def delete(value: Int): Unit = {
var p = head
val updates: Array[Node] = new Array[Node](skipListLevel)

//try to locate the given node with the value
for (i <- skipListLevel - 1 to 0 by -1) {
while (p.forwards(i) != null && p.forwards(i).data < value) {
p = p.forwards(i)
}
updates(i) = p
}

if (p.forwards(0) != null && p.forwards(0).data == value) {
//find the value node, start to delete the node from the skip list
for (i <- skipListLevel - 1 to 0 by -1) {
if (updates(i).forwards(i) != null && updates(i).forwards(i).data == value) {
updates(i).forwards(i) = updates(i).forwards(i).forwards(i)
}
}
}

}

def randomLevel(): Int = {
var level = 1
for (i <- Range(1, MAX_LEVEL)) {
if (random.nextInt() % 2 == 1) {
level += 1
}
}

level
}

def mkString(): String = {
val builder = new StringBuilder
var p = head
while (p.forwards(0) != null) {
p = p.forwards(0)
builder.append(p.data)
}

builder.mkString
}
}


44 changes: 44 additions & 0 deletions scala/src/test/scala/ch17_skip_list/SkipListTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package ch17_skip_list

import org.scalatest.{FlatSpec, Matchers}

import scala.util.Random

class SkipListTest extends FlatSpec with Matchers {

behavior of "SkipListTest"

it should "insert skip list" in {
val list = new SkipList()
for (i <- Range(0, 10)) {
list.insert(i)
}

list.mkString() should equal("0123456789")
}

it should "delete skip list" in {
val list = new SkipList()
for (i <- Range(0, 10)) {
list.insert(i)
}

list.delete(5)
list.mkString() should equal("012346789")
}

it should "find value in skip list" in {
val list = new SkipList()
val length = 5000
val array = new Array[Int](length)
val rnd = new Random()
for (i <- Range(0, length)) {
array(i) = rnd.nextInt(length)
list.insert(array(i))
}

assert(list.find(array(rnd.nextInt(length - 1))).isDefined)
assert(list.find(array(rnd.nextInt(length - 1)) + length + 1).isEmpty)

}
}

0 comments on commit bd41e13

Please sign in to comment.