-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathskipList.java
More file actions
290 lines (241 loc) · 8.75 KB
/
Copy pathskipList.java
File metadata and controls
290 lines (241 loc) · 8.75 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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
/* Author's Name: Mubasshir Al Shahriar
Relevant Course : CSCI 313: Data Structures */
import java.util.*;
public class skipList
{
/* Creating this node class to store key and value. Next, prev, above, below - these 4 nodes will be used to create levels and towers for our skip list. */
private static class Node
{
int key;
String value;
Node next, prev, above, below;
Node(int key, String value)
{
this.key = key;
this.value = value;
}
}
private Node head;
private Node tail;
private int height = 0;
private Random rand = new Random(); /* Using this random number generator for the coin flip logic to decide which nodes will exist on next level. */
/* This constructor creates the bottom level (S0) of our skip list. We can use head and tail here as sentinels (like negative and positive infinity sentinels we saw in the lecture slides). */
public skipList()
{
head = new Node(Integer.MIN_VALUE, null);
tail = new Node(Integer.MAX_VALUE, null);
head.next = tail;
tail.prev = head;
}
// Coin flip method
private boolean coinFlip()
{
return rand.nextBoolean();
}
/* This method searches and returns the base level node with key <= k. */
private Node skipSearch(int key)
{
Node curr = head; /* Setting current node as head so that it starts at the top-left of the list. */
while (true)
{
while (curr.next.key <= key) /* While loop allows it to keep going towards right until the next key is larger than the one we need. */
{
curr = curr.next;
}
if (curr.below != null) /* Moves to the next level of the same tower until it reaches the base level (S0). */
{
curr = curr.below;
}
else
{
break;
}
}
return curr.key == key ? curr : null;
}
/* We will need to use this method in our in main function to print the result of the search in output and returns position corresponding to key k in the bottom list, or null if k is not found. I am using the similar logic of skipSearch method for this one. */
public Node skipSearchPrint(int key)
{
Node curr = head;
while (true)
{
while (curr.next.key <= key)
{
curr = curr.next;
}
if (curr.below != null)
{
curr = curr.below;
}
else
{
break;
}
}
return curr.key == key ? curr : null;
}
// This method can be used to insert a new key-value pair.
public void skipInsert(int key, String value)
{
Stack<Node> path = new Stack<>(); /* This variable "path" will keep track of the insert positions at each level. */
Node curr = head;
/* First, it searches and finds the position where the new pair needs to be inserted. */
while (curr != null)
{
while (curr.next.key < key)
{
curr = curr.next;
}
path.push(curr);
curr = curr.below;
}
/* After finding the correct position, it inserts at bottom. */
Node belowNode = null;
boolean insertUp = true;
int level = 0;
while (insertUp && !path.isEmpty())
{
curr = path.pop();
Node newNode = new Node(key, value);
newNode.prev = curr;
newNode.next = curr.next;
curr.next.prev = newNode;
curr.next = newNode;
newNode.below = belowNode;
if (belowNode != null) belowNode.above = newNode;
belowNode = newNode;
insertUp = coinFlip();
level++;
}
if (insertUp) /* This adds new level if needed. If the coin flips (through rand function) more times than the number of levels we have, then it create a new top level, and adds sentinels. */
{
height++;
Node newHead = new Node(Integer.MIN_VALUE, null);
Node newTail = new Node(Integer.MAX_VALUE, null);
newHead.next = newTail;
newTail.prev = newHead;
newHead.below = head;
head.above = newHead;
newTail.below = tail;
tail.above = newTail;
head = newHead;
tail = newTail;
Node newNode = new Node(key, value);
newNode.prev = head;
newNode.next = tail;
head.next = newNode;
tail.prev = newNode;
newNode.below = belowNode;
belowNode.above = newNode;
}
}
// This method removes all levels of key
public void skipRemove(int key)
{
Node node = skipSearch(key); /* First I am using skipSearch() method to find the base-level node for key k. */
while (node != null) /* Then, it traverses upward and removes each level of the tower. */
{
node.prev.next = node.next;
node.next.prev = node.prev;
node = node.above;
}
}
// This method prints the skip list.
public void printList()
{
System.out.println("Full Skip List:");
/* First, it goes down to the base level (S0) of the list. */
Node temp = head;
while (temp.below != null)
{
temp = temp.below;
}
/* Then it builds base level keys list which I will use as reference later to determine if an element was eliminated in next level and I should put "--" in place of that eliminated element. */
List<Integer> baseKeys = new ArrayList<>();
Node currBase = temp;
while (currBase != null)
{
baseKeys.add(currBase.key);
currBase = currBase.next;
}
/* Next, it prints each level */
int extendedHeight = height + 1;
System.out.print("S" + extendedHeight + ": ");
for (int i = 0; i < baseKeys.size(); i++)
{
if (i == 0)
{
System.out.print("[-inf]");
}
else if (i == baseKeys.size() - 1)
{
System.out.print("[+inf]");
}
else
{
System.out.print("[--]");
}
if (i != baseKeys.size() - 1)
{
System.out.print(" --- ");
}
}
System.out.println();
Node levelStart = head;
int level = height;
while (levelStart != null)
{
System.out.print("S" + level + ": ");
Node curr = levelStart;
int b = 0;
while (b < baseKeys.size())
{
int currentKey = baseKeys.get(b);
if (curr != null && curr.key == currentKey)
{
// Key matches: print the real key
String display = (curr.key == Integer.MIN_VALUE) ? "-inf" :
(curr.key == Integer.MAX_VALUE) ? "+inf" :
Integer.toString(curr.key);
System.out.print("[" + display + "]");
curr = curr.next; // Moving to the next node (rightward) at this same level
}
else
{
/* If no matching node found at this level (meaning the element was eliminated by the rand function), it prints [--] so that all present elements stays in correct places. */
System.out.print("[--]");
}
// After each box, it prints connectors
if (b != baseKeys.size() - 1)
{
System.out.print(" --- ");
}
b++;
}
System.out.println();
levelStart = levelStart.below; // Moving to the next (lower) level
level--;
}
}
/* Main method of the program with hardcoded sequence of 10 arbitrary integers. */
public static void main(String[] args)
{
skipList sl = new skipList(); // Creating a new skip list.
int[] keys = {35, 23, 17, 48, 15, 89, 41, 60, 28, 33};
for (int k : keys)
{
sl.skipInsert(k, "V" + k);
}
System.out.println("Initial Skip List with Hard-coded Key-Value Pairs:");
sl.printList();
System.out.println("\nInserting and Printing a New Key-Value Pair (21, V21):");
sl.skipInsert(21, "V21");
sl.printList();
System.out.println("\nSearching For Key 28:");
Node result = sl.skipSearchPrint(28);
System.out.println(result != null ? "Found at Base Level: (" + result.key + "," + result.value + ")" : "Not found.");
System.out.println("\nRemoving Key 28 and Printing Again:");
sl.skipRemove(28);
sl.printList();
}
}