forked from Varal7/random_bst
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathzip_trees.py
More file actions
176 lines (150 loc) · 4.97 KB
/
Copy pathzip_trees.py
File metadata and controls
176 lines (150 loc) · 4.97 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
""" Zip tree Implementation in Python
"""
import os
from random import Random
# TODO: Remove self.parent
class _ZipNode:
"""Zip Node"""
def __init__(self, elem, rank,
parent=None, left=None, right=None):
self.elem = elem
self.rank = rank
self.parent = parent
self.left = left
self.right = right
def __repr__(self):
return str((self.elem, self.rank))
class ZipTree:
"""
ZipTree
"""
def __init__(self, seed=0):
self.random = Random(seed)
self.root = None
def insert(self, elem):
rank = self.randomRank()
x = _ZipNode(elem, rank)
cur = self.root
while cur is not None and (rank < cur.rank or (rank == cur.rank and elem > cur.elem)):
prev = cur
cur = cur.left if elem < cur.elem else cur.right
if cur is self.root:
self.root = x
elif elem < prev.elem:
prev.left = x
else:
prev.right = x
if cur is None:
x.left = x.right = None
return
if elem < cur.elem:
x.right = cur
else:
x.left = cur
prev = x
while cur is not None:
fix = prev
if cur.elem < elem:
done = False
while not done:
prev = cur
cur = cur.right
if cur is None or cur.elem > elem:
done = True
else:
done = False
while not done:
prev = cur
cur = cur.left
if cur is None or cur.elem < elem:
done = True
if fix.elem > elem or (fix == x and prev.elem > elem):
fix.left = cur
else:
fix.right = cur
def delete(self, elem):
cur = self.root
while elem != cur.elem:
prev = cur
cur = cur.left if elem < cur.elem else cur.right
left = cur.left
right = cur.right
if left is None:
cur = right
elif right is None:
cur = left
elif left.rank >= right.rank:
cur = left
else:
cur = right
if self.root.elem == elem:
self.root = cur
elif elem < prev.elem:
prev.left = cur
else:
prev.right = cur
while left is not None and right is not None:
if left.rank >= right.rank:
done = False
while not done:
prev = left
left = left.right
if left is None or left.rank < right.rank:
done = True
prev.right = right
else:
done = False
while not done:
prev = right
right = right.left
if right is None or left.rank >= right.rank:
done = True
prev.left = left
def randomRank(self):
height = 1
while self.random.randint(1, 2) != 1:
height += 1
return height
def _find_node(self, elem, node, parent=None):
while True:
if node is None or elem == node.elem:
return node, parent
elif elem < node.elem:
node, parent = node.left, node
else:
node, parent = node.right, node
def __contains__(self, elem):
"""Return True iff elem is found in tree, else False."""
node = self._find_node(elem, self.root)[0]
return node is not None
def check(self):
"""Check zip tree invariants."""
nodes = [(self.root, None, None)]
while nodes:
node, min_bound, max_bound = nodes.pop()
if node:
if min_bound: assert min_bound < node.elem
if max_bound: assert node.elem < max_bound
if node.left:
assert node.elem > node.left.elem
assert node.rank > node.left.rank
if node.right:
assert node.elem < node.right.elem
assert node.rank >= node.right.rank
if node.parent:
parent = node.parent
assert parent.left == node or parent.right == node
nodes.append((node.left, min_bound, node.elem))
nodes.append((node.right, node.elem, max_bound))
def __repr__(self):
"""Return a string representation of treap."""
lines = []
nodes = [(self.root, 0)]
while nodes:
node, indent = nodes.pop()
name = str(node) if node else 'None'
lines.append(' ' * indent + name)
if node:
nodes.append((node.right, indent + 1))
nodes.append((node.left, indent + 1))
return os.linesep.join(lines)