added redblack
This commit is contained in:
parent
911ae73ddf
commit
9b19f8e4f5
1 changed files with 263 additions and 0 deletions
263
redblack.py
Executable file
263
redblack.py
Executable file
|
@ -0,0 +1,263 @@
|
|||
#!/usr/bin/env python3
|
||||
# vim: set ts=2 sw=2 et tw=80:
|
||||
|
||||
import sys
|
||||
|
||||
class Tree:
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
root.parent = self
|
||||
|
||||
def set_root(self, root):
|
||||
self.root = root
|
||||
root.parent = self
|
||||
|
||||
|
||||
class Node:
|
||||
def __init__(self, k):
|
||||
self.key = k
|
||||
self.isBlack = True
|
||||
self.left = None
|
||||
self.right = None
|
||||
self.parent = None
|
||||
|
||||
def set_left(self, kNode):
|
||||
if kNode is not None:
|
||||
kNode.parent = self
|
||||
self.left = kNode
|
||||
|
||||
def set_right(self, kNode):
|
||||
if kNode is not None:
|
||||
kNode.parent = self
|
||||
self.right = kNode
|
||||
|
||||
|
||||
def is_black(node):
|
||||
return node is None or node.isBlack
|
||||
|
||||
|
||||
def insert(tree, node):
|
||||
y = None
|
||||
x = tree
|
||||
# Imperatively find place to insert node
|
||||
while x is not None:
|
||||
y = x
|
||||
if node.key < x.key:
|
||||
x = x.left
|
||||
else:
|
||||
x = x.right
|
||||
|
||||
node.parent = y
|
||||
if y is None:
|
||||
tree = node
|
||||
elif node.key < y.key:
|
||||
y.left = node
|
||||
else:
|
||||
y.right = node
|
||||
node.isBlack = False
|
||||
insert_fixup(tree, node)
|
||||
|
||||
|
||||
def sibling(node):
|
||||
if node.parent.left is node:
|
||||
return node.parent.right
|
||||
else:
|
||||
return node.parent.left
|
||||
|
||||
|
||||
def uncle(node):
|
||||
return sibling(node.parent)
|
||||
|
||||
|
||||
def right_rotate(x):
|
||||
# assume x is not None
|
||||
# assume x.left is not None
|
||||
# assume not root (x.parent is not None
|
||||
p = x.parent
|
||||
t = x.left
|
||||
x.set_left(t.right)
|
||||
t.set_right(x)
|
||||
if isinstance(p, Tree):
|
||||
p.set_root(t)
|
||||
elif p.left is x:
|
||||
p.set_left(t)
|
||||
else:
|
||||
p.set_right(t)
|
||||
|
||||
|
||||
def left_rotate(x):
|
||||
# assume x is not None
|
||||
# assume x.right is not None
|
||||
# assume not root (x.parent is not None)
|
||||
p = x.parent
|
||||
t = x.right
|
||||
x.set_right(t.left)
|
||||
t.set_left(x)
|
||||
if isinstance(p, Tree):
|
||||
p.set_root(t)
|
||||
elif p.left is x:
|
||||
p.set_left(t)
|
||||
else:
|
||||
p.set_right(t)
|
||||
|
||||
|
||||
def insert_fixup(tree, node):
|
||||
if isinstance(node.parent, Tree): # if root
|
||||
node.isBlack = True
|
||||
elif is_black(node.parent):
|
||||
# no fixup needed
|
||||
pass
|
||||
elif isinstance(node.parent.parent, Tree):
|
||||
node.parent.isBlack = True
|
||||
elif not is_black(uncle(node)):
|
||||
node.parent.parent.isBlack = False
|
||||
node.parent.isBlack = True
|
||||
if sibling(node.parent) is not None:
|
||||
sibling(node.parent).isBlack = True
|
||||
insert_fixup(tree, node.parent)
|
||||
else:
|
||||
if node.parent.parent.left is node.parent:
|
||||
if node.parent.right is node:
|
||||
left_rotate(node.parent)
|
||||
node = node.left
|
||||
right_rotate(node.parent.parent)
|
||||
else:
|
||||
if node.parent.left is node:
|
||||
right_rotate(node.parent)
|
||||
node = node.right
|
||||
left_rotate(node.parent.parent)
|
||||
node.parent.isBlack = True
|
||||
if sibling(node) is not None:
|
||||
sibling(node).isBlack = False
|
||||
insert_fixup(tree, node.parent)
|
||||
|
||||
|
||||
# Complexity (worst): Theta(n)
|
||||
def search(tree, k):
|
||||
if tree is None:
|
||||
return None
|
||||
elif tree.key == k:
|
||||
return tree
|
||||
elif k < tree.key:
|
||||
return search(tree.left, k)
|
||||
else:
|
||||
return search(tree.right, k)
|
||||
|
||||
|
||||
# Complexity (worst): Theta(n)
|
||||
def min(t):
|
||||
if t is None:
|
||||
return None
|
||||
while t.left is not None:
|
||||
t = t.left
|
||||
return t
|
||||
|
||||
|
||||
# Complexity (worst): Theta(n)
|
||||
def max(t):
|
||||
if t is None:
|
||||
return None
|
||||
while t.right is not None:
|
||||
t = t.right
|
||||
return t
|
||||
|
||||
|
||||
def successor(t):
|
||||
if t.right is not None:
|
||||
return min(t.right)
|
||||
while t.parent is not None:
|
||||
if t.parent.left == t:
|
||||
return t.parent
|
||||
else:
|
||||
t = t.parent
|
||||
return None
|
||||
|
||||
|
||||
def predecessor(t):
|
||||
if t.left is not None:
|
||||
return max(t.left)
|
||||
while t is not None:
|
||||
if t.parent.right == t:
|
||||
return t.parent
|
||||
else:
|
||||
t = t.parent
|
||||
return None
|
||||
|
||||
###############################################################################
|
||||
# Code for printing trees, ignore this
|
||||
|
||||
|
||||
class Canvas:
|
||||
def __init__(self, width):
|
||||
self.line_width = width
|
||||
self.canvas = []
|
||||
|
||||
def put_char(self, x, y, c):
|
||||
if x < self.line_width:
|
||||
pos = y * self.line_width + x
|
||||
l = len(self.canvas)
|
||||
if pos < l:
|
||||
self.canvas[pos] = c
|
||||
else:
|
||||
self.canvas[l:] = [' '] * (pos - l)
|
||||
self.canvas.append(c)
|
||||
|
||||
def print_out(self):
|
||||
i = 0
|
||||
for c in self.canvas:
|
||||
sys.stdout.write(c)
|
||||
i = i + 1
|
||||
if i % self.line_width == 0:
|
||||
sys.stdout.write('\n')
|
||||
if i % self.line_width != 0:
|
||||
sys.stdout.write('\n')
|
||||
|
||||
|
||||
def print_binary_r(t, x, y, canvas):
|
||||
max_y = y
|
||||
if t.left is not None:
|
||||
x, max_y, lx, rx = print_binary_r(t.left, x, y + 2, canvas)
|
||||
x = x + 1
|
||||
for i in range(rx, x):
|
||||
canvas.put_char(i, y + 1, '/')
|
||||
|
||||
middle_l = x
|
||||
for c in (str(t.key) + ("B" if t.isBlack else "R")):
|
||||
canvas.put_char(x, y, c)
|
||||
x = x + 1
|
||||
middle_r = x
|
||||
|
||||
if t.right is not None:
|
||||
canvas.put_char(x, y + 1, '\\')
|
||||
x = x + 1
|
||||
x0, max_y2, lx, rx = print_binary_r(t.right, x, y + 2, canvas)
|
||||
if max_y2 > max_y:
|
||||
max_y = max_y2
|
||||
for i in range(x, lx):
|
||||
canvas.put_char(i, y + 1, '\\')
|
||||
x = x0
|
||||
|
||||
return (x, max_y, middle_l, middle_r)
|
||||
|
||||
|
||||
def print_tree(t):
|
||||
print_w(t, 80)
|
||||
|
||||
|
||||
def print_w(t, width):
|
||||
canvas = Canvas(width)
|
||||
print_binary_r(t, 0, 0, canvas)
|
||||
canvas.print_out()
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = [x for x in sys.argv[1:]]
|
||||
T = Tree(Node(int(args[0])))
|
||||
for i in range(1, len(args)):
|
||||
print_tree(T.root)
|
||||
print("\nInsert " + str(args[i]) + ":")
|
||||
insert(T.root, Node(int(args[i])))
|
||||
print_tree(T.root)
|
||||
|
Reference in a new issue