This repository has been archived on 2021-10-31. You can view files and clone it, but cannot push or open issues or pull requests.
DSA/GA3/ga3.tex
2019-05-14 08:57:03 +02:00

671 lines
14 KiB
TeX

% vim: set ts=2 sw=2 tw=80 et:
\documentclass[12pt]{article}
\usepackage[margin=3cm]{geometry}
\usepackage{xcolor}
\usepackage{lmodern}
\usepackage{listings}
\title{Graded Assignment 3 -- DSA}
\author{Claudio Maggioni}
\setlength{\parindent}{0cm}
% listings configuration
\lstset{
basicstyle=\small\ttfamily,
frame=shadowbox,
rulesepcolor=\color{black},
columns=fullflexible,
commentstyle=\color{gray},
keywordstyle=\bfseries,
keywords={,while,if,elif,else,FUNCTION,return,for,from,to,TRUE,FALSE},
mathescape=true,
aboveskip=2em,
captionpos=b,
abovecaptionskip=1em,
belowcaptionskip=1em
}
\begin{document}
\maketitle
\tableofcontents
\lstlistoflistings
\newpage
\section{Exercise 1}
{\small\ttfamily
\begin{verbatim}
12
Insert 6:
12
/
6
Insert 1:
12
/
6
/
1
Insert 7:
12
///
6
/ \
1 7
Insert 4:
12
///
6
/// \
1 7
\
4
Insert 11:
12
//////
6
/// \
1 7
\ \
4 11
Insert 15:
12
////// \
6 15
/// \
1 7
\ \
4 11
Insert 9:
12
//////// \
6 15
/// \
1 7
\ \\\
4 11
/
9
Insert 5:
12
//////// \
6 15
///// \
1 7
\ \\\
4 11
\ /
5 9
Insert 13:
12
//////// \\\\
6 15
///// \ /
1 7 13
\ \\\
4 11
\ /
5 9
Insert 8:
12
////////// \\\\
6 15
///// \ /
1 7 13
\ \\\\\
4 11
\ /
5 9
/
8
Insert 14:
12
////////// \\\\\\\
6 15
///// \ ////
1 7 13
\ \\\\\ \
4 11 14
\ /
5 9
/
8
Insert 3:
12
////////// \\\\\\\
6 15
/////// \ ////
1 7 13
\\\ \\\\\ \
4 11 14
/ \ /
3 5 9
/
8
Insert 10:
12
///////////// \\\\\\\
6 15
/////// \ ////
1 7 13
\\\ \\\\\\\\ \
4 11 14
/ \ ////
3 5 9
/ \
8 10
Insert 2:
12
///////////// \\\\\\\
6 15
///////// \ ////
1 7 13
\\\\\ \\\\\\\\ \
4 11 14
/ \ ////
3 5 9
/ / \
2 8 10
Delete 6:
12
/////////// \\\\\\\
7 15
///////// \\\\\\\\ ////
1 11 13
\\\\\ //// \
4 9 14
/ \ / \
3 5 8 10
/
2
Delete 2:
12
/////////// \\\\\\\
7 15
/////// \\\\\\\\ ////
1 11 13
\\\ //// \
4 9 14
/ \ / \
3 5 8 10
Delete 12:
15
////
13
/////////// \
7 14
/////// \\\\\\\\
1 11
\\\ ////
4 9
/ \ / \
3 5 8 10
\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}
{\small\ttfamily
\begin{verbatim}
12B
Insert 6:
12B
/
6R
Insert 1:
6B
/ \
1R 12R
Insert 7:
6B
/ \\\\
1B 12B
/
7R
Insert 4:
6B
//// \\\\
1B 12B
\ /
4R 7R
Insert 11:
6B
//// \\\\
1B 11B
\ / \
4R 7R 12R
Insert 15:
6B
//// \\\\
1B 11R
\ / \
4R 7B 12B
\
15R
Insert 9:
6B
//// \\\\\\\
1B 11R
\ //// \
4R 7B 12B
\ \
9R 15R
Insert 5:
6B
//// \\\\\\\
4B 11R
/ \ //// \
1R 5R 7B 12B
\ \
9R 15R
Insert 13:
6B
//// \\\\\\\
4B 11R
/ \ //// \\\\\
1R 5R 7B 13B
\ / \
9R 12R 15R
Insert 8:
6B
//// \\\\\\\\\\
4B 11R
/ \ //// \\\\\
1R 5R 8B 13B
/ \ / \
7R 9R 12R 15R
Insert 14:
11B
////////// \\\\\
6R 13R
//// \\\\ / \\\\\
4B 8B 12B 15B
/ \ / \ /
1R 5R 7R 9R 14R
Insert 3:
11B
////////// \\\\\
6B 13B
//// \\\\ / \\\\\
4R 8B 12B 15B
//// \ / \ /
1B 5B 7R 9R 14R
\
3R
Insert 10:
11B
////////////// \\\\\
6B 13B
//// \\\\ / \\\\\
4R 8R 12B 15B
//// \ / \ /
1B 5B 7B 9B 14R
\ \
3R 10R
Insert 2:
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)$ (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
since it is a constant factor (since the maximum height is $2\log(n)$ and the minimum one is $\log(n)$.
\section{Exercise 3}
\begin{lstlisting}[caption=Solution for exercise 3, label={lst:ex3}]
FUNCTION JOIN-INTERVALS(X)
if X.length == 0:
return
for i from 1 to X.length:
if i % 2 == 1:
X[i] $\gets$ (X[i], 1)
else:
X[i] $\gets$ (X[i], -1)
$\textit{sort X in place by 1st tuple element in O(n log(n))}$
c $\gets$ 1
n $\gets$ 0
start $\gets$ X[1][1]
for i from 2 to X.length:
c $\gets$ c + X[i][2]
if c == 0:
X[2 * n + 1] $\gets$ start
X[2 * n + 2] $\gets$ X[i][1]
if i < X.length:
start $\gets$ X[i+1][1]
n $\gets$ n + 1
X.length $\gets$ 2 * n
\end{lstlisting}
%
The complexity of this algorithm is $O(n\log(n))$ since the sorting is in
$\Theta(n\log(n))$ and the union operation afterwards is $\Theta(n)$.
\section{Bonus}
The number of possible trees with $n$ nodes can be defined recursively. The
number of trees with 0 or 1 node is clearly 1, since there is no freedom in
arranging any remaining elements as children. For $n$ nodes, this number can be
defined as the the sum, for each $x, y \in N_0$ s.t. $x + y = n - 1$, of the
number of trees with $x$ nodes times the number of trees with $y$ nodes. We
consider only $n - 1$ nodes since one node must be the root of the tree.
Using math notation, the number $T_n$ of trees with $n$ nodes can be expressed
as:
$$T_n = 1 \hspace{1cm} n = 0 \lor n = 1$$
$$T_n = \sum_{i = 0}^{n-1} T_i T_{n-1-i} \hspace{1cm} n \geq 2$$
\end{document}