-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdesign_skiplist.py
93 lines (74 loc) · 2.67 KB
/
design_skiplist.py
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
'''
Design a Skiplist without using any built-in libraries.
A skiplist is a data structure that takes O(log(n)) time to add, erase and search. Comparing with treap and red-black tree which has the same function and performance, the code length of Skiplist can be comparatively short and the idea behind Skiplists is just simple linked lists.
For example, we have a Skiplist containing [30,40,50,60,70,90] and we want to add 80 and 45 into it. The Skiplist works this way:
'''
import random
class ListNode:
__slots__ = ('val', 'next', 'down')
def __init__(self, val):
self.val = val
self.next = None
self.down = None
class Skiplist:
def __init__(self):
# sentinel nodes to keep code simple
node = ListNode(float('-inf'))
node.next = ListNode(float('inf'))
self.levels = [node]
def search(self, target: int) -> bool:
level = self.levels[-1]
while level:
node = level
while node.next.val < target:
node = node.next
if node.next.val == target:
return True
level = node.down
return False
def add(self, num: int) -> None:
stack = []
level = self.levels[-1]
while level:
node = level
while node.next.val < num:
node = node.next
stack.append(node)
level = node.down
heads = True
down = None
while stack and heads:
prev = stack.pop()
node = ListNode(num)
node.next = prev.next
node.down = down
prev.next = node
down = node
# flip a coin to stop or continue with the next level
heads = random.randint(0, 1)
# add a new level if we got to the top with heads
if not stack and heads:
node = ListNode(float('-inf'))
node.next = ListNode(num)
node.down = self.levels[-1]
node.next.next = ListNode(float('inf'))
node.next.down = down
self.levels.append(node)
def erase(self, num: int) -> bool:
stack = []
level = self.levels[-1]
while level:
node = level
while node.next.val < num:
node = node.next
if node.next.val == num:
stack.append(node)
level = node.down
if not stack:
return False
for node in stack:
node.next = node.next.next
# remove the top level if it's empty
while len(self.levels) > 1 and self.levels[-1].next.next is None:
self.levels.pop()
return True