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} \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} \section{Exercise 2}
\subsection{Point A} \subsection{Point A}
@ -262,22 +380,22 @@ Insert 11:
4R 7R 12R 4R 7R 12R
Insert 15: Insert 15:
11B 6B
//// \ //// \\\\
6R 12B 1B 11R
//// \ \ \ / \
1B 7B 15R 4R 7B 12B
\ \
4R 15R
Insert 9: Insert 9:
11B 6B
/////// \ //// \\\\\\\
6R 12B 1B 11R
//// \ \ \ //// \
1B 7B 15R 4R 7B 12B
\ \ \ \
4R 9R 9R 15R
Insert 5: Insert 5:
6B 6B
@ -289,82 +407,216 @@ Insert 5:
9R 15R 9R 15R
Insert 13: Insert 13:
11B 6B
/////// \\\\\ //// \\\\\\\
6R 13B 4B 11R
//// \ / \ / \ //// \\\\\
4B 7B 12R 15R 1R 5R 7B 13B
/ \ \ \ / \
1R 5R 9R 9R 12R 15R
Insert 8: Insert 8:
8B 6B
//// \\\\ //// \\\\\\\\\\
6R 11R 4B 11R
//// \ / \\\\\ / \ //// \\\\\
4B 7R 9R 13B 1R 5R 8B 13B
/ \ / \ / \ / \
1R 5R 12R 15R 7R 9R 12R 15R
Insert 14: Insert 14:
8B 11B
//// \\\\ ////////// \\\\\
6B 11B 6R 13R
//// \ / \\\\\ //// \\\\ / \\\\\
4B 7R 9B 13B 4B 8B 12B 15B
/ \ / \\\\\ / \ / \ /
1R 5R 12B 15B 1R 5R 7R 9R 14R
/
14R
Insert 3: Insert 3:
6B 11B
//// \\\\ ////////// \\\\\
4B 8R 6B 13B
//// \ / \\\\ //// \\\\ / \\\\\
1B 5B 7B 11B 4R 8B 12B 15B
\ / \\\\\ //// \ / \ /
3R 9B 13B 1B 5B 7R 9R 14R
/ \\\\\ \
12B 15B 3R
/
14R
Insert 10: Insert 10:
6B 11B
//// \\\\ ////////////// \\\\\
4B 8R 6B 13B
//// \ / \\\\\\\\ //// \\\\ / \\\\\
1B 5B 7B 11B 4R 8R 12B 15B
\ ///// \\\\\ //// \ / \ /
3R 9B 13B 1B 5B 7B 9B 14R
\ / \\\\\ \ \
10R 12B 15B 3R 10R
/
14R
Insert 2: Insert 2:
6B 11B
//// \\\\ ////////////// \\\\\
4B 8R 6B 13B
//// \ / \\\\\\\\ //// \\\\ / \\\\\
2B 5B 7B 11B 4R 8R 12B 15B
/ \ ///// \\\\\ //// \ / \ /
1R 3R 9B 13B 2B 5B 7B 9B 14R
\ / \\\\\ / \ \
10R 12B 15B 1R 3R 10R
/
14R
\end{verbatim}% \end{verbatim}%
}% }%
% %
Assume every empty branch has as a child a black leaf node. 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} \subsection{Point B}
A red-black tree of n distinct elements has an height between $\log(n)$ 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 and $2\log(n)$ (as professor Carzaniga said in class) thanks to the red-black
complexity is $\log(n)$ since finding the right place to insert is as complex as 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 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). 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 In asymptotic terms, the uneven height of leaves in the tree does not make a difference
@ -393,6 +645,7 @@ FUNCTION JOIN-INTERVALS(X)
if c == 0: if c == 0:
X[2 * n + 1] $\gets$ start X[2 * n + 1] $\gets$ start
X[2 * n + 2] $\gets$ X[i][1] X[2 * n + 2] $\gets$ X[i][1]
if i < X.length:
start $\gets$ X[i+1][1] start $\gets$ X[i+1][1]
n $\gets$ n + 1 n $\gets$ n + 1
X.length $\gets$ 2 * n X.length $\gets$ 2 * n

View file

@ -107,14 +107,12 @@ def insert_fixup(tree, node):
elif is_black(node.parent): elif is_black(node.parent):
# no fixup needed # no fixup needed
pass pass
elif isinstance(node.parent.parent, Tree): elif not isinstance(node.parent.parent, Tree) and not is_black(uncle(node)):
node.parent.isBlack = True
elif not is_black(uncle(node)):
node.parent.parent.isBlack = False node.parent.parent.isBlack = False
node.parent.isBlack = True node.parent.isBlack = True
if sibling(node.parent) is not None: if sibling(node.parent) is not None:
sibling(node.parent).isBlack = True sibling(node.parent).isBlack = True
insert_fixup(tree, node.parent) insert_fixup(tree, node.parent.parent)
else: else:
if node.parent.parent.left is node.parent: if node.parent.parent.left is node.parent:
if node.parent.right is node: if node.parent.right is node:
@ -129,59 +127,6 @@ def insert_fixup(tree, node):
node.parent.isBlack = True node.parent.isBlack = True
if sibling(node) is not None: if sibling(node) is not None:
sibling(node).isBlack = False 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 # 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)