forked from wangzheng0822/algo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9392777
commit bd41e13
Showing
2 changed files
with
143 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
||
} | ||
} |