# @file tree.007.py
# @ingroup experimental
# Recursive red & black tree.
# @date 01/05/2023
class Color:
RED = 0
BLACK = 1
class Node:
def __init__(self, data):
self.child = [None] * 2
self.color = Color.RED
self.data = data
def __setitem__(self, i, v):
self.child[i] = v
def __getitem__(self, i):
return self.child[i]
def is_red(x):
return x and x.color == Color.RED
def try_setcolor(x, v):
if not x:
return False
x.color = v
return True
def rotate(x, R):
L = 1-R
y = x[L]
x[L] = y[R]
y[R] = x
return y
class Tree:
def __init__(self):
self.root = None
## Insert. ##
def insert(self, key):
self.root = Tree._insert(self.root, key)
self.root.color = Color.BLACK
def _insert(root, key):
if not root:
return Node(key)
elif key < root.data:
root[0] = Tree._insert(root[0], key)
elif key > root.data:
root[1] = Tree._insert(root[1], key)
else:
raise KeyError('Key already exists!')
return Tree._insert_balance(root)
def _insert_balance(root):
if Node.is_red(root):
pass
elif Node.is_red(root[0]):
root = Tree._insert_balance_lower(root, 0)
elif Node.is_red(root[1]):
root = Tree._insert_balance_lower(root, 1)
return root
def _insert_balance_lower(root, R):
L = 1-R
if Node.is_red(root[R][L]):
# 4-node normalize (1).
root[R] = Node.rotate(root[R], R)
if Node.is_red(root[R][R]):
# 4-node normalize (2).
root[R].color = Color.BLACK
root.color = Color.RED
root = Node.rotate(root, L)
if Node.is_red(root[L]):
# 4-node split.
root[L].color = Color.BLACK
root[R].color = Color.BLACK
root.color = Color.RED
return root
## Remove. ##
def remove(self, key):
self.root = Tree._remove(self.root, key, [None])
def _remove(root, key, last):
if not root:
raise KeyError('Key does not exist!')
elif key < root.data:
root[0] = Tree._remove(root[0], key, last)
elif key > root.data:
root[1] = Tree._remove(root[1], key, last)
elif root[1]:
# Interior node; delete inorder successor.
root[1] = Tree._delete_minimum(root[1], root, last)
else:
return Tree._delete_node(root)
return Tree._remove_balance(root, last)
def _delete_minimum(root, interior, last):
if root[0]:
root[0] = Tree._delete_minimum(root[0], interior, last)
else:
interior.data = root.data
return Tree._delete_node(root)
return Tree._remove_balance(root, last)
def _delete_node(root):
if Node.try_setcolor(root[0], Color.BLACK):
return root[0]
if Node.try_setcolor(root[1], Color.BLACK):
return root[1]
return None
def _remove_balance(root, last):
is_short = False
if not (root[0] or root[1]):
# Root is terminal node.
pass
elif root[0] is last[0]:
root, is_short = Tree._remove_balance_lower(root, 0)
elif root[1] is last[0]:
root, is_short = Tree._remove_balance_lower(root, 1)
# Signal parent.
last[0] = root if is_short else None
return root
def _remove_balance_lower(root, R):
L = 1-R
if Node.is_red(root[L]):
# 3-node parent; sibling is 'far' middle.
root[L].color = Color.BLACK
root.color = Color.RED
root = Node.rotate(root, R)
root[R], _ = Tree._remove_balance_close(root[R], R, L)
return root, False
return Tree._remove_balance_close(root, R, L)
def _remove_balance_close(root, R, L):
is_short = False
if Node.is_red(root[L][R]):
# Borrow sibling (1).
root[L][R].color = Color.BLACK
root[L].color = Color.RED
root[L] = Node.rotate(root[L], L)
if Node.is_red(root[L][L]):
# Borrow sibling (2).
root[L][L].color = Color.BLACK
root[L].color = root.color
root.color = Color.BLACK
root = Node.rotate(root, R)
else:
# Borrow parent/shorten sibling.
is_short = not Node.is_red(root)
root[L].color = Color.RED
root.color = Color.BLACK
return root, is_short
## Utility. ##
def inorder(self):
return Tree._inorder(self.root)
def _inorder(root):
if root:
yield from Tree._inorder(root[0])
yield root.data
yield from Tree._inorder(root[1])
def levelorder(self):
q = [self.root]
while q.count(None) != len(q):
nodes = q
q = []
r = []
for node in nodes:
assert node, 'Tree unbalanced!'
assert node.color == Color.BLACK, 'Color violation!'
if Node.is_red(node[0]):
# 3-node; left-leaning.
r.append([node[0].data, node.data])
q.extend((node[0][0], node[0][1], node[1]))
elif Node.is_red(node[1]):
# 3-node; right-leaning.
r.append([node.data, node[1].data])
q.extend((node[0], node[1][0], node[1][1]))
else:
# 2-node.
r.append([node.data])
q.extend((node[0], node[1]))
yield r
### Testing. ###
import random
def pretty_print_tree(t):
lines = (''.join(map(str, x)) for x in t.levelorder())
print('>', next(lines, None))
for line in lines:
print(' ', line)
n = 2**3-1
a = list(range(1, 1+n))
t = Tree()
b = random.sample(a, k=n)
print('Insert:', b)
for i in b:
t.insert(i)
pretty_print_tree(t)
b = list(t.inorder())
assert a == b, 'Bad order!'
b = random.sample(a, k=n)
print('Remove:', b)
for i in b:
t.remove(i)
pretty_print_tree(t)
IyBAZmlsZSB0cmVlLjAwNy5weQojIEBpbmdyb3VwIGV4cGVyaW1lbnRhbAojIFJlY3Vyc2l2ZSByZWQgJiBibGFjayB0cmVlLgojIEBkYXRlIDAxLzA1LzIwMjMKCmNsYXNzIENvbG9yOgogICAgUkVEID0gMAogICAgQkxBQ0sgPSAxCgpjbGFzcyBOb2RlOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGRhdGEpOgogICAgICAgIHNlbGYuY2hpbGQgPSBbTm9uZV0gKiAyCiAgICAgICAgc2VsZi5jb2xvciA9IENvbG9yLlJFRAogICAgICAgIHNlbGYuZGF0YSA9IGRhdGEKCiAgICBkZWYgX19zZXRpdGVtX18oc2VsZiwgaSwgdik6CiAgICAgICAgc2VsZi5jaGlsZFtpXSA9IHYKCiAgICBkZWYgX19nZXRpdGVtX18oc2VsZiwgaSk6CiAgICAgICAgcmV0dXJuIHNlbGYuY2hpbGRbaV0KCiAgICBkZWYgaXNfcmVkKHgpOgogICAgICAgIHJldHVybiB4IGFuZCB4LmNvbG9yID09IENvbG9yLlJFRAoKICAgIGRlZiB0cnlfc2V0Y29sb3IoeCwgdik6CiAgICAgICAgaWYgbm90IHg6CiAgICAgICAgICAgIHJldHVybiBGYWxzZQogICAgICAgIHguY29sb3IgPSB2CiAgICAgICAgcmV0dXJuIFRydWUKCiAgICBkZWYgcm90YXRlKHgsIFIpOgogICAgICAgIEwgPSAxLVIKICAgICAgICB5ID0geFtMXQogICAgICAgIHhbTF0gPSB5W1JdCiAgICAgICAgeVtSXSA9IHgKICAgICAgICByZXR1cm4geQoKY2xhc3MgVHJlZToKICAgIGRlZiBfX2luaXRfXyhzZWxmKToKICAgICAgICBzZWxmLnJvb3QgPSBOb25lCgogICAgIyMgSW5zZXJ0LiAjIwoKICAgIGRlZiBpbnNlcnQoc2VsZiwga2V5KToKICAgICAgICBzZWxmLnJvb3QgPSBUcmVlLl9pbnNlcnQoc2VsZi5yb290LCBrZXkpCiAgICAgICAgc2VsZi5yb290LmNvbG9yID0gQ29sb3IuQkxBQ0sKCiAgICBkZWYgX2luc2VydChyb290LCBrZXkpOgogICAgICAgIGlmIG5vdCByb290OgogICAgICAgICAgICByZXR1cm4gTm9kZShrZXkpCiAgICAgICAgZWxpZiBrZXkgPCByb290LmRhdGE6CiAgICAgICAgICAgIHJvb3RbMF0gPSBUcmVlLl9pbnNlcnQocm9vdFswXSwga2V5KQogICAgICAgIGVsaWYga2V5ID4gcm9vdC5kYXRhOgogICAgICAgICAgICByb290WzFdID0gVHJlZS5faW5zZXJ0KHJvb3RbMV0sIGtleSkKICAgICAgICBlbHNlOgogICAgICAgICAgICByYWlzZSBLZXlFcnJvcignS2V5IGFscmVhZHkgZXhpc3RzIScpCiAgICAgICAgcmV0dXJuIFRyZWUuX2luc2VydF9iYWxhbmNlKHJvb3QpCgogICAgZGVmIF9pbnNlcnRfYmFsYW5jZShyb290KToKICAgICAgICBpZiBOb2RlLmlzX3JlZChyb290KToKICAgICAgICAgICAgcGFzcwogICAgICAgIGVsaWYgTm9kZS5pc19yZWQocm9vdFswXSk6CiAgICAgICAgICAgIHJvb3QgPSBUcmVlLl9pbnNlcnRfYmFsYW5jZV9sb3dlcihyb290LCAwKQogICAgICAgIGVsaWYgTm9kZS5pc19yZWQocm9vdFsxXSk6CiAgICAgICAgICAgIHJvb3QgPSBUcmVlLl9pbnNlcnRfYmFsYW5jZV9sb3dlcihyb290LCAxKQogICAgICAgIHJldHVybiByb290CgogICAgZGVmIF9pbnNlcnRfYmFsYW5jZV9sb3dlcihyb290LCBSKToKICAgICAgICBMID0gMS1SCiAgICAgICAgaWYgTm9kZS5pc19yZWQocm9vdFtSXVtMXSk6CiAgICAgICAgICAgICMgNC1ub2RlIG5vcm1hbGl6ZSAoMSkuCiAgICAgICAgICAgIHJvb3RbUl0gPSBOb2RlLnJvdGF0ZShyb290W1JdLCBSKQogICAgICAgIGlmIE5vZGUuaXNfcmVkKHJvb3RbUl1bUl0pOgogICAgICAgICAgICAjIDQtbm9kZSBub3JtYWxpemUgKDIpLgogICAgICAgICAgICByb290W1JdLmNvbG9yID0gQ29sb3IuQkxBQ0sKICAgICAgICAgICAgcm9vdC5jb2xvciA9IENvbG9yLlJFRAogICAgICAgICAgICByb290ID0gTm9kZS5yb3RhdGUocm9vdCwgTCkKICAgICAgICBpZiBOb2RlLmlzX3JlZChyb290W0xdKToKICAgICAgICAgICAgIyA0LW5vZGUgc3BsaXQuCiAgICAgICAgICAgIHJvb3RbTF0uY29sb3IgPSBDb2xvci5CTEFDSwogICAgICAgICAgICByb290W1JdLmNvbG9yID0gQ29sb3IuQkxBQ0sKICAgICAgICAgICAgcm9vdC5jb2xvciA9IENvbG9yLlJFRAogICAgICAgIHJldHVybiByb290CgogICAgIyMgUmVtb3ZlLiAjIwoKICAgIGRlZiByZW1vdmUoc2VsZiwga2V5KToKICAgICAgICBzZWxmLnJvb3QgPSBUcmVlLl9yZW1vdmUoc2VsZi5yb290LCBrZXksIFtOb25lXSkKCiAgICBkZWYgX3JlbW92ZShyb290LCBrZXksIGxhc3QpOgogICAgICAgIGlmIG5vdCByb290OgogICAgICAgICAgICByYWlzZSBLZXlFcnJvcignS2V5IGRvZXMgbm90IGV4aXN0IScpCiAgICAgICAgZWxpZiBrZXkgPCByb290LmRhdGE6CiAgICAgICAgICAgIHJvb3RbMF0gPSBUcmVlLl9yZW1vdmUocm9vdFswXSwga2V5LCBsYXN0KQogICAgICAgIGVsaWYga2V5ID4gcm9vdC5kYXRhOgogICAgICAgICAgICByb290WzFdID0gVHJlZS5fcmVtb3ZlKHJvb3RbMV0sIGtleSwgbGFzdCkKICAgICAgICBlbGlmIHJvb3RbMV06CiAgICAgICAgICAgICMgSW50ZXJpb3Igbm9kZTsgZGVsZXRlIGlub3JkZXIgc3VjY2Vzc29yLgogICAgICAgICAgICByb290WzFdID0gVHJlZS5fZGVsZXRlX21pbmltdW0ocm9vdFsxXSwgcm9vdCwgbGFzdCkKICAgICAgICBlbHNlOgogICAgICAgICAgICByZXR1cm4gVHJlZS5fZGVsZXRlX25vZGUocm9vdCkKICAgICAgICByZXR1cm4gVHJlZS5fcmVtb3ZlX2JhbGFuY2Uocm9vdCwgbGFzdCkKCiAgICBkZWYgX2RlbGV0ZV9taW5pbXVtKHJvb3QsIGludGVyaW9yLCBsYXN0KToKICAgICAgICBpZiByb290WzBdOgogICAgICAgICAgICByb290WzBdID0gVHJlZS5fZGVsZXRlX21pbmltdW0ocm9vdFswXSwgaW50ZXJpb3IsIGxhc3QpCiAgICAgICAgZWxzZToKICAgICAgICAgICAgaW50ZXJpb3IuZGF0YSA9IHJvb3QuZGF0YQogICAgICAgICAgICByZXR1cm4gVHJlZS5fZGVsZXRlX25vZGUocm9vdCkKICAgICAgICByZXR1cm4gVHJlZS5fcmVtb3ZlX2JhbGFuY2Uocm9vdCwgbGFzdCkKCiAgICBkZWYgX2RlbGV0ZV9ub2RlKHJvb3QpOgogICAgICAgIGlmIE5vZGUudHJ5X3NldGNvbG9yKHJvb3RbMF0sIENvbG9yLkJMQUNLKToKICAgICAgICAgICAgcmV0dXJuIHJvb3RbMF0KICAgICAgICBpZiBOb2RlLnRyeV9zZXRjb2xvcihyb290WzFdLCBDb2xvci5CTEFDSyk6CiAgICAgICAgICAgIHJldHVybiByb290WzFdCiAgICAgICAgcmV0dXJuIE5vbmUKCiAgICBkZWYgX3JlbW92ZV9iYWxhbmNlKHJvb3QsIGxhc3QpOgogICAgICAgIGlzX3Nob3J0ID0gRmFsc2UKICAgICAgICBpZiBub3QgKHJvb3RbMF0gb3Igcm9vdFsxXSk6CiAgICAgICAgICAgICMgUm9vdCBpcyB0ZXJtaW5hbCBub2RlLgogICAgICAgICAgICBwYXNzCiAgICAgICAgZWxpZiByb290WzBdIGlzIGxhc3RbMF06CiAgICAgICAgICAgIHJvb3QsIGlzX3Nob3J0ID0gVHJlZS5fcmVtb3ZlX2JhbGFuY2VfbG93ZXIocm9vdCwgMCkKICAgICAgICBlbGlmIHJvb3RbMV0gaXMgbGFzdFswXToKICAgICAgICAgICAgcm9vdCwgaXNfc2hvcnQgPSBUcmVlLl9yZW1vdmVfYmFsYW5jZV9sb3dlcihyb290LCAxKQogICAgICAgICMgU2lnbmFsIHBhcmVudC4KICAgICAgICBsYXN0WzBdID0gcm9vdCBpZiBpc19zaG9ydCBlbHNlIE5vbmUKICAgICAgICByZXR1cm4gcm9vdAoKICAgIGRlZiBfcmVtb3ZlX2JhbGFuY2VfbG93ZXIocm9vdCwgUik6CiAgICAgICAgTCA9IDEtUgogICAgICAgIGlmIE5vZGUuaXNfcmVkKHJvb3RbTF0pOgogICAgICAgICAgICAjIDMtbm9kZSBwYXJlbnQ7IHNpYmxpbmcgaXMgJ2ZhcicgbWlkZGxlLgogICAgICAgICAgICByb290W0xdLmNvbG9yID0gQ29sb3IuQkxBQ0sKICAgICAgICAgICAgcm9vdC5jb2xvciA9IENvbG9yLlJFRAogICAgICAgICAgICByb290ID0gTm9kZS5yb3RhdGUocm9vdCwgUikKICAgICAgICAgICAgcm9vdFtSXSwgXyA9IFRyZWUuX3JlbW92ZV9iYWxhbmNlX2Nsb3NlKHJvb3RbUl0sIFIsIEwpCiAgICAgICAgICAgIHJldHVybiByb290LCBGYWxzZQogICAgICAgIHJldHVybiBUcmVlLl9yZW1vdmVfYmFsYW5jZV9jbG9zZShyb290LCBSLCBMKQoKICAgIGRlZiBfcmVtb3ZlX2JhbGFuY2VfY2xvc2Uocm9vdCwgUiwgTCk6CiAgICAgICAgaXNfc2hvcnQgPSBGYWxzZQogICAgICAgIGlmIE5vZGUuaXNfcmVkKHJvb3RbTF1bUl0pOgogICAgICAgICAgICAjIEJvcnJvdyBzaWJsaW5nICgxKS4KICAgICAgICAgICAgcm9vdFtMXVtSXS5jb2xvciA9IENvbG9yLkJMQUNLCiAgICAgICAgICAgIHJvb3RbTF0uY29sb3IgPSBDb2xvci5SRUQKICAgICAgICAgICAgcm9vdFtMXSA9IE5vZGUucm90YXRlKHJvb3RbTF0sIEwpCiAgICAgICAgaWYgTm9kZS5pc19yZWQocm9vdFtMXVtMXSk6CiAgICAgICAgICAgICMgQm9ycm93IHNpYmxpbmcgKDIpLgogICAgICAgICAgICByb290W0xdW0xdLmNvbG9yID0gQ29sb3IuQkxBQ0sKICAgICAgICAgICAgcm9vdFtMXS5jb2xvciA9IHJvb3QuY29sb3IKICAgICAgICAgICAgcm9vdC5jb2xvciA9IENvbG9yLkJMQUNLCiAgICAgICAgICAgIHJvb3QgPSBOb2RlLnJvdGF0ZShyb290LCBSKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgICMgQm9ycm93IHBhcmVudC9zaG9ydGVuIHNpYmxpbmcuCiAgICAgICAgICAgIGlzX3Nob3J0ID0gbm90IE5vZGUuaXNfcmVkKHJvb3QpCiAgICAgICAgICAgIHJvb3RbTF0uY29sb3IgPSBDb2xvci5SRUQKICAgICAgICAgICAgcm9vdC5jb2xvciA9IENvbG9yLkJMQUNLCiAgICAgICAgcmV0dXJuIHJvb3QsIGlzX3Nob3J0CgogICAgIyMgVXRpbGl0eS4gIyMKCiAgICBkZWYgaW5vcmRlcihzZWxmKToKICAgICAgICByZXR1cm4gVHJlZS5faW5vcmRlcihzZWxmLnJvb3QpCgogICAgZGVmIF9pbm9yZGVyKHJvb3QpOgogICAgICAgIGlmIHJvb3Q6CiAgICAgICAgICAgIHlpZWxkIGZyb20gVHJlZS5faW5vcmRlcihyb290WzBdKQogICAgICAgICAgICB5aWVsZCByb290LmRhdGEKICAgICAgICAgICAgeWllbGQgZnJvbSBUcmVlLl9pbm9yZGVyKHJvb3RbMV0pCgogICAgZGVmIGxldmVsb3JkZXIoc2VsZik6CiAgICAgICAgcSA9IFtzZWxmLnJvb3RdCiAgICAgICAgd2hpbGUgcS5jb3VudChOb25lKSAhPSBsZW4ocSk6CiAgICAgICAgICAgIG5vZGVzID0gcQogICAgICAgICAgICBxID0gW10KICAgICAgICAgICAgciA9IFtdCiAgICAgICAgICAgIGZvciBub2RlIGluIG5vZGVzOgogICAgICAgICAgICAgICAgYXNzZXJ0IG5vZGUsICdUcmVlIHVuYmFsYW5jZWQhJwogICAgICAgICAgICAgICAgYXNzZXJ0IG5vZGUuY29sb3IgPT0gQ29sb3IuQkxBQ0ssICdDb2xvciB2aW9sYXRpb24hJwogICAgICAgICAgICAgICAgaWYgTm9kZS5pc19yZWQobm9kZVswXSk6CiAgICAgICAgICAgICAgICAgICAgIyAzLW5vZGU7IGxlZnQtbGVhbmluZy4KICAgICAgICAgICAgICAgICAgICByLmFwcGVuZChbbm9kZVswXS5kYXRhLCBub2RlLmRhdGFdKQogICAgICAgICAgICAgICAgICAgIHEuZXh0ZW5kKChub2RlWzBdWzBdLCBub2RlWzBdWzFdLCBub2RlWzFdKSkKICAgICAgICAgICAgICAgIGVsaWYgTm9kZS5pc19yZWQobm9kZVsxXSk6CiAgICAgICAgICAgICAgICAgICAgIyAzLW5vZGU7IHJpZ2h0LWxlYW5pbmcuCiAgICAgICAgICAgICAgICAgICAgci5hcHBlbmQoW25vZGUuZGF0YSwgbm9kZVsxXS5kYXRhXSkKICAgICAgICAgICAgICAgICAgICBxLmV4dGVuZCgobm9kZVswXSwgbm9kZVsxXVswXSwgbm9kZVsxXVsxXSkpCiAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICMgMi1ub2RlLgogICAgICAgICAgICAgICAgICAgIHIuYXBwZW5kKFtub2RlLmRhdGFdKQogICAgICAgICAgICAgICAgICAgIHEuZXh0ZW5kKChub2RlWzBdLCBub2RlWzFdKSkKICAgICAgICAgICAgeWllbGQgcgoKIyMjIFRlc3RpbmcuICMjIwoKaW1wb3J0IHJhbmRvbQoKZGVmIHByZXR0eV9wcmludF90cmVlKHQpOgogICAgbGluZXMgPSAoJycuam9pbihtYXAoc3RyLCB4KSkgZm9yIHggaW4gdC5sZXZlbG9yZGVyKCkpCiAgICBwcmludCgnPicsIG5leHQobGluZXMsIE5vbmUpKQogICAgZm9yIGxpbmUgaW4gbGluZXM6CiAgICAgICAgcHJpbnQoJyAnLCBsaW5lKQoKbiA9IDIqKjMtMQphID0gbGlzdChyYW5nZSgxLCAxK24pKQp0ID0gVHJlZSgpCgpiID0gcmFuZG9tLnNhbXBsZShhLCBrPW4pCnByaW50KCdJbnNlcnQ6JywgYikKZm9yIGkgaW4gYjoKICAgIHQuaW5zZXJ0KGkpCiAgICBwcmV0dHlfcHJpbnRfdHJlZSh0KQoKYiA9IGxpc3QodC5pbm9yZGVyKCkpCmFzc2VydCBhID09IGIsICdCYWQgb3JkZXIhJwoKYiA9IHJhbmRvbS5zYW1wbGUoYSwgaz1uKQpwcmludCgnUmVtb3ZlOicsIGIpCmZvciBpIGluIGI6CiAgICB0LnJlbW92ZShpKQogICAgcHJldHR5X3ByaW50X3RyZWUodCk=