-
Notifications
You must be signed in to change notification settings - Fork 0
/
SkipList.java
159 lines (146 loc) · 5.27 KB
/
SkipList.java
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
import java.util.Random;
public final class SkipList {
static final int MAX_LEVEL = 32;
static final double Prob = 0.5;
final Node head = new Node(Integer.MIN_VALUE); // set head to the smallest integer
final Node tail = new Node(Integer.MAX_VALUE); // set tail to the biggest integer
public SkipList() {
for (int i = 0; i < head.next.length; i++) {
head.next[i] = tail; // initialize all layers with only the head and the tail
}
}
// generate a random level number that provides a balancing property
// Top levels are chosen so that the expected number of nodes in each level’s list decreases exponentially
private int randomLevel() {
int level = 1;
for (int i = 0; i < MAX_LEVEL; i++) {
Random rand = new Random();
float f = rand.nextFloat();
if (f <= Prob) {
level++;
}
else {
return level;
}
}
return level;
}
int find(int x, Node[] preds, Node[] succs) {
int key = x;
// will return -1 if not found in any layer
int layerFound = -1;
// start traversal from the head sentinel
Node pred = head;
for (int level = MAX_LEVEL; level >= 0; level--) {
Node curr = pred.next[level];
// compare key with curr.key until hit tail, i.e. a MAX_VALUE
while (key > curr.key) {
pred = curr;
curr = pred.next[level];
}
if (layerFound == -1 && key == curr.key) {
layerFound = level;
}
preds[level] = pred;
succs[level] = curr;
}
return layerFound;
}
boolean add(int x) {
// initialize pred and succ arrays
Node[] preds = (Node[]) new Node[MAX_LEVEL + 1];
Node[] succs = (Node[]) new Node[MAX_LEVEL + 1];
int layerFound = find(x, preds, succs);
// Case 1 - element found in the list, unsuccessful add
if (layerFound != -1) {
return false;
}
// Case 2 - not found in the list, create a new node with a random top-level
int topLevel = randomLevel();
Node newNode = new Node(x, topLevel);
for (int level = 0; level <= topLevel; level++) {
newNode.next[level] = succs[level];
preds[level].next[level] = newNode;
}
// successful add
return true;
}
boolean remove(int x) {
Node victim = null;
int topLevel = -1;
// initialize pred and succ arrays
Node[] preds = (Node[]) new Node[MAX_LEVEL + 1];
Node[] succs = (Node[]) new Node[MAX_LEVEL + 1];
// use find to check if node is in list
int layerFound = find(x, preds, succs);
if (layerFound != -1) {
victim = succs[layerFound];
topLevel = victim.topLevel;
// remove links to victim, top-down
for (int level = topLevel; level >= 0; level--) {
preds[level].next[level] = victim.next[level];
}
// successful delete
return true;
}
// did not find a matching node, unsuccessful delete
return false;
}
boolean contains(int x) {
Node[] preds = (Node[]) new Node[MAX_LEVEL + 1];
Node[] succs = (Node[]) new Node[MAX_LEVEL + 1];
int layerFound = find(x, preds, succs);
return layerFound != -1;
}
private static final class Node {
final int item;
final int key;
final Node[] next;
private int topLevel;
// sentinel node constructor (head and tail)
public Node(int key) {
this.item = key;
this.key = key;
this.next = new Node[MAX_LEVEL + 1];
this.topLevel = MAX_LEVEL;
}
public Node(int x, int height) {
this.item = x;
this.key = x;
this.next = new Node[height + 1];
this.topLevel = height;
}
}
public static void main(String [] args) {
SkipList list = new SkipList();
int n = 2000000;
int[] a = new int[n];
Random rand = new Random();
long start;
long end;
for (int i = 0; i < n; i++) {
a[i] = rand.nextInt(n);
}
// test add
start = System.currentTimeMillis();
for (int i = 0; i < n; i++) {
list.add(a[i]);
}
end = System.currentTimeMillis();
System.out.println("Java sequential add() " + n + " nodes, time: " + (end - start) / 1000.0 + " s");
// test contains
start = System.currentTimeMillis();
for (int i = 0; i < n; i++) {
list.contains(a[i]);
}
end = System.currentTimeMillis();
System.out.println("Java sequential contains() " + n + " nodes, time: " + (end - start) / 1000.0 + " s");
// test remove
start = System.currentTimeMillis();
for (int i = 0; i < n; i++) {
list.remove(a[i]);
}
end = System.currentTimeMillis();
System.out.println("Java sequential remove() " + n + " nodes, time: " + (end - start) / 1000.0 + " s");
}
}