-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxfasttrie.py
133 lines (114 loc) · 3.56 KB
/
xfasttrie.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
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
"""An implementation of Willard's X-Fast tries
This structure is able to store w-bit integers with O(log w) time searches
and O(w) time addition/removal
D. E. Willard. Log-logarithmic worst-case range queries are possible in
space Theta(n). Information Processing Letters, 17, 81-84. 1984.
"""
from base import BaseSet
from binarytrie import BinaryTrie
from linearhashtable import LinearHashTable
from utils import new_array, w
class XFastTrie(BinaryTrie):
class Node(BinaryTrie.Node):
def __init__(self):
super(XFastTrie.Node, self).__init__()
self.prefix = 0
def __eq__(self, other):
return self.prefix == other.prefix
def __hash__(self):
return hash(self.prefix)
def _new_node(self):
return XFastTrie.Node()
def __init__(self):
super(XFastTrie, self).__init__()
self.nil = self._new_node()
self.t = new_array(w+1)
for i in range(w+1):
self.t[i] = LinearHashTable()
self.t[0].add(self.r)
def add(self, x):
if super(XFastTrie, self).add(x):
ix = int(x)
u = self.r.child[(ix >> w-1) & 1]
for i in range(1, w+1):
u.prefix = ix >> w-i
self.t[i].add(u)
if i < w:
c = (ix >> w-i-1) & 1
u = u.child[c]
return True
return False
def find(self, x):
ix = int(x)
l, h = 0, w+1
u = self.r
q = self._new_node()
while h-l > 1:
i = (l+h)/2
q.prefix = ix >> w-i
v = self.t[i].find(q)
if v is None:
h = i
else:
u = v
l = i
if l == w: return u.x
c = ix >> (w-l-1) & 1
pred = [u.jump.prev, u.jump][c]
if pred.next is None: return None
return pred.next.x
# TODO: Too much duplication with find(x)
def find_node(self, x):
ix = int(x)
l, h = 0, w+1
u = self.r
q = self._new_node()
while h-l > 1:
i = (l+h)/2
q.prefix = ix >> w-i
v = self.t[i].find(q)
if v is None:
h = i
else:
u = v
l = i
if l == w: return u
c = ix >> (w-l-1) & 1
pred = [u.jump.prev, u.jump][c]
if pred.next is None: return None
return pred.next
def remove(self, x):
# 1 - fine leaf, u, containing x
ix = int(x)
i = 0
u = self.r
while i < w:
c = ix >> (w-i-1) & 1
u = u.child[c]
if u is None: return False
i += 1
# 2 - remove u from linked list
pred = u.prev
succ = u.next
pred.next = succ
succ.prev = pred
u.next = u.prev = None
v = u
# 3 - delete nodes on path to u
while v is not self.r and v.left is None and v.right is None:
if v is v.parent.left:
v.parent.left = None
else:
v.parent.right = None
self.t[i].remove(v)
i -= 1
v = v.parent
# 4 - update jump pointers
v.jump = [pred, succ][v.left is None]
v = v.parent
while v is not None:
if v.jump is u:
v.jump = [pred, succ][v.left is None]
v = v.parent
self.n -= 1
return True