Radix
def longest_common_base(x: str, y: str) -> str:
if not x or not y:
return ""
i = 0
while i < len(x) and i < len(y):
if x[i] != y[i]:
return x[:i]
i += 1
return x[:i]
def one_prefixes_other(x: str, y: str) -> bool:
if not x or not y:
return True
return first_prefixes_second(x, y) or first_prefixes_second(y, x)
def first_prefixes_second(x: str, y: str) -> bool:
if not x:
return True
if not y:
return False
if len(y) < len(x):
return False
return y[:len(x)] == x
class Node:
def __init__(self, value: str = "", leaf: bool = True):
if not isinstance(value, str):
raise "wrong value type"
self.value = value
self.leaf = leaf
self.children = {}
self.size = 0
def is_node(self) -> bool:
return not self.leaf
def insert_leaf_node_without_checking(self, new_node):
if self.leaf:
raise "cannot insert into a leaf"
self.children[new_node.value] = new_node
def contains_leaf(self, s: str) -> bool:
if s in self.children:
n: Node = self.children[s]
return n.leaf
for child_string in self.children:
if first_prefixes_second(child_string, s):
sub = s[len(child_string):]
n: Node = self.children[child_string]
return n.contains_leaf(sub)
return False
def insert_and_check(self, new_string: str) -> bool:
# return true if one word is found to be a prefix of another.
if self.leaf:
raise "cannot insert into a leaf"
common_base = ""
for child_string in self.children:
if first_prefixes_second(new_string, child_string):
return True
child_node = self.children[child_string]
if child_node.is_node():
if first_prefixes_second(child_string, new_string):
# This does not mean there is a dupicate, because it is a node.
sub = new_string[len(child_string):]
return child_node.insert_and_check(sub)
else:
# it is a leaf. Check if this leaf is a prefix of the new value
if first_prefixes_second(child_string, new_string):
return True
b = longest_common_base(child_string, new_string)
if len(b) > len(common_base):
common_base = b
if len(common_base) > 0:
new_child = Node(common_base, leaf=False)
to_del = []
for child_string in self.children:
node: Node = self.children[child_string]
if node.is_node():
continue
if first_prefixes_second(common_base, child_string):
to_del.append(child_string)
node.value = node.value[len(common_base):]
new_child.insert_leaf_node_without_checking(node)
# don't forget to still insert the word that just arrived.
sub = new_string[len(common_base):]
new_child.insert_leaf_node_without_checking(Node(sub, leaf=True))
for s in to_del:
del self.children[s]
self.children[common_base] = new_child
else:
self.children[new_string] = Node(new_string, leaf=True)
self.size += 1
return False
class Radix:
def __init__(self):
self.head = Node(value = "", leaf = False)
def insert_and_check(self, v: str) -> bool:
# return true if one word is found to be a prefix of another.
return self.head.insert_and_check(v)
def size(self) -> int:
return self.head.size
def contains_leaf(self, s: str) -> bool:
return self.head.contains_leaf(s)