Fixed GA3 again

This commit is contained in:
Claudio Maggioni 2019-05-13 16:00:21 +02:00
parent 4bca4b25ac
commit d37f05664d
4 changed files with 507 additions and 130 deletions

Binary file not shown.

View file

@ -222,6 +222,124 @@ Delete 12:
\end{verbatim}
}
The following printout was obtained by running the following BST implementation.with the following command:
\begin{verbatim}
./tree.py 12 6 1 7 4 11 15 9 5 13 8 14 3 10 2 \| 6 2 12
\end{verbatim}
\begin{lstlisting}[caption=BST implementation, language=python]
#!/usr/bin/env python3
# $\textbf{\color{red}vim}$: set ts=2 sw=2 et tw=80:
import sys
class Node:
def __init__(self, k):
self.key = k
self.left = None
self.right = None
self.parent = None
def set_left(self, kNode):
kNode.parent = self
self.left = kNode
def set_right(self, kNode):
kNode.parent = self
self.right = kNode
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)
def insert(t, k):
insert_node(t, Node(k))
def insert_node(t, node):
if node.key < t.key:
if t.left is None:
t.set_left(node)
else:
insert_node(t.left, node)
else:
if t.right is None:
t.set_right(node)
else:
insert_node(t.right, node)
def root_insert(t, k):
if t is None:
return k
if k.key > t.key:
t.set_right(root_insert(t.right, k))
return left_rotate(t)
else:
t.set_left(root_insert(t.left, k))
return right_rotate(t)
def unlink_me(node, to_link):
if node.parent == None:
tr = node
node.key = to_link.key
node.left = to_link.left
node.right = to_link.right
return node
elif node.parent.left == node:
node.parent.left = to_link
return to_link
else:
node.parent.right = to_link
return to_link
def delete(t, k):
to_delete = search(t, k)
if to_delete is None:
return
elif to_delete.left is None:
unlink_me(to_delete, to_delete.right)
elif to_delete.right is None:
unlink_me(to_delete, to_delete.left)
else:
if abs(to_delete.left.key - to_delete.key) < abs(to_delete.right.key -
to_delete.key):
ins = to_delete.right
new_branch = unlink_me(to_delete, to_delete.left)
insert_node(new_branch, ins)
else:
ins = to_delete.left
new_branch = unlink_me(to_delete, to_delete.right)
insert_node(new_branch, ins)
if __name__ == "__main__":
args = [x for x in sys.argv[1:]]
T = Node(int(args[0]))
for i in range(1, len(args)):
if args[i] == '|':
break
print_tree(T)
print("\nInsert " + str(args[i]) + ":")
insert(T, int(args[i]))
for i in range(i+1, len(args)):
print_tree(T)
print("\nDelete " + str(args[i]) + ":")
delete(T, int(args[i]))
print_tree(T)
\end{lstlisting}
\section{Exercise 2}
\subsection{Point A}
@ -262,22 +380,22 @@ Insert 11:
4R 7R 12R
Insert 15:
11B
//// \
6R 12B
//// \ \
1B 7B 15R
\
4R
6B
//// \\\\
1B 11R
\ / \
4R 7B 12B
\
15R
Insert 9:
11B
/////// \
6R 12B
//// \ \
1B 7B 15R
\ \
4R 9R
6B
//// \\\\\\\
1B 11R
\ //// \
4R 7B 12B
\ \
9R 15R
Insert 5:
6B
@ -289,82 +407,216 @@ Insert 5:
9R 15R
Insert 13:
11B
/////// \\\\\
6R 13B
//// \ / \
4B 7B 12R 15R
/ \ \
1R 5R 9R
6B
//// \\\\\\\
4B 11R
/ \ //// \\\\\
1R 5R 7B 13B
\ / \
9R 12R 15R
Insert 8:
8B
//// \\\\
6R 11R
//// \ / \\\\\
4B 7R 9R 13B
/ \ / \
1R 5R 12R 15R
6B
//// \\\\\\\\\\
4B 11R
/ \ //// \\\\\
1R 5R 8B 13B
/ \ / \
7R 9R 12R 15R
Insert 14:
8B
//// \\\\
6B 11B
//// \ / \\\\\
4B 7R 9B 13B
/ \ / \\\\\
1R 5R 12B 15B
/
14R
11B
////////// \\\\\
6R 13R
//// \\\\ / \\\\\
4B 8B 12B 15B
/ \ / \ /
1R 5R 7R 9R 14R
Insert 3:
6B
//// \\\\
4B 8R
//// \ / \\\\
1B 5B 7B 11B
\ / \\\\\
3R 9B 13B
/ \\\\\
12B 15B
/
14R
11B
////////// \\\\\
6B 13B
//// \\\\ / \\\\\
4R 8B 12B 15B
//// \ / \ /
1B 5B 7R 9R 14R
\
3R
Insert 10:
6B
//// \\\\
4B 8R
//// \ / \\\\\\\\
1B 5B 7B 11B
\ ///// \\\\\
3R 9B 13B
\ / \\\\\
10R 12B 15B
/
14R
11B
////////////// \\\\\
6B 13B
//// \\\\ / \\\\\
4R 8R 12B 15B
//// \ / \ /
1B 5B 7B 9B 14R
\ \
3R 10R
Insert 2:
6B
//// \\\\
4B 8R
//// \ / \\\\\\\\
2B 5B 7B 11B
/ \ ///// \\\\\
1R 3R 9B 13B
\ / \\\\\
10R 12B 15B
/
14R
11B
////////////// \\\\\
6B 13B
//// \\\\ / \\\\\
4R 8R 12B 15B
//// \ / \ /
2B 5B 7B 9B 14R
/ \ \
1R 3R 10R
\end{verbatim}%
}%
%
Assume every empty branch has as a child a black leaf node.
The following printout was generated by this red-black tree implementation in python with the following command:
\begin{verbatim}
python3 redblack.py 12 6 1 7 4 11 15 9 5 13 8 14 3 10 2
\end{verbatim}
\begin{lstlisting}[caption=Red-black tree implementation, language=python]
#!/usr/bin/env python3
# $\textbf{\color{red}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):
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):
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 not isinstance(node.parent.parent, Tree) and 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.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
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)
\end{lstlisting}
\subsection{Point B}
A red-black tree of n distinct elements has an height between $\log(n)$
and $2\log(n)$ thanks to the red-black tree invariant. The worst-case insertion
complexity is $\log(n)$ since finding the right place to insert is as complex as
and $2\log(n)$ (as professor Carzaniga said in class) thanks to the red-black
tree invariant. The worst-case insertion complexity is $\log(n)$ since
finding the right place to insert is as complex as
a regular tree (i.e. logarithmic) and the ``fixup'' operation is logarithmic as
well (the tree traversal is logarithmic while operations in each iteration are constant).
In asymptotic terms, the uneven height of leaves in the tree does not make a difference
@ -393,7 +645,8 @@ FUNCTION JOIN-INTERVALS(X)
if c == 0:
X[2 * n + 1] $\gets$ start
X[2 * n + 2] $\gets$ X[i][1]
start $\gets$ X[i+1][1]
if i < X.length:
start $\gets$ X[i+1][1]
n $\gets$ n + 1
X.length $\gets$ 2 * n
\end{lstlisting}

View file

@ -107,14 +107,12 @@ def insert_fixup(tree, node):
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)):
elif not isinstance(node.parent.parent, Tree) and 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)
insert_fixup(tree, node.parent.parent)
else:
if node.parent.parent.left is node.parent:
if node.parent.right is node:
@ -129,59 +127,6 @@ def insert_fixup(tree, node):
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

179
GA3/tree.py Executable file
View file

@ -0,0 +1,179 @@
#!/usr/bin/env python3
# vim: set ts=2 sw=2 et tw=80:
import sys
class Node:
def __init__(self, k):
self.key = k
self.left = None
self.right = None
self.parent = None
def set_left(self, kNode):
kNode.parent = self
self.left = kNode
def set_right(self, kNode):
kNode.parent = self
self.right = kNode
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)
def insert(t, k):
insert_node(t, Node(k))
def insert_node(t, node):
if node.key < t.key:
if t.left is None:
t.set_left(node)
else:
insert_node(t.left, node)
else:
if t.right is None:
t.set_right(node)
else:
insert_node(t.right, node)
def root_insert(t, k):
if t is None:
return k
if k.key > t.key:
t.set_right(root_insert(t.right, k))
return left_rotate(t)
else:
t.set_left(root_insert(t.left, k))
return right_rotate(t)
def unlink_me(node, to_link):
if node.parent == None:
tr = node
node.key = to_link.key
node.left = to_link.left
node.right = to_link.right
return node
elif node.parent.left == node:
node.parent.left = to_link
return to_link
else:
node.parent.right = to_link
return to_link
def delete(t, k):
to_delete = search(t, k)
if to_delete is None:
return
elif to_delete.left is None:
unlink_me(to_delete, to_delete.right)
elif to_delete.right is None:
unlink_me(to_delete, to_delete.left)
else:
if abs(to_delete.left.key - to_delete.key) < abs(to_delete.right.key -
to_delete.key):
ins = to_delete.right
new_branch = unlink_me(to_delete, to_delete.left)
insert_node(new_branch, ins)
else:
ins = to_delete.left
new_branch = unlink_me(to_delete, to_delete.right)
insert_node(new_branch, ins)
###############################################################################
# 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):
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 = Node(int(args[0]))
for i in range(1, len(args)):
if args[i] == '|':
break
print_tree(T)
print("\nInsert " + str(args[i]) + ":")
insert(T, int(args[i]))
for i in range(i+1, len(args)):
print_tree(T)
print("\nDelete " + str(args[i]) + ":")
delete(T, int(args[i]))
print_tree(T)