2017-01-07 22:31:41 +01:00
|
|
|
\chapter{Tree algorithms}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
\index{tree}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
A \key{tree} is a connected, acyclic graph
|
2017-02-05 12:40:54 +01:00
|
|
|
that consists of $n$ nodes and $n-1$ edges.
|
2017-01-07 22:31:41 +01:00
|
|
|
Removing any edge from a tree divides it
|
|
|
|
into two components,
|
|
|
|
and adding any edge to a tree creates a cycle.
|
|
|
|
Moreover, there is always a unique path between any
|
2017-02-17 21:13:30 +01:00
|
|
|
two nodes of a tree.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
For example, the following tree consists of 7 nodes and 6 edges:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.9]
|
|
|
|
\node[draw, circle] (1) at (0,3) {$1$};
|
|
|
|
\node[draw, circle] (2) at (2,3) {$2$};
|
|
|
|
\node[draw, circle] (3) at (0,1) {$4$};
|
|
|
|
\node[draw, circle] (4) at (2,1) {$5$};
|
|
|
|
\node[draw, circle] (5) at (4,1) {$6$};
|
|
|
|
\node[draw, circle] (6) at (-2,3) {$7$};
|
|
|
|
\node[draw, circle] (7) at (-2,1) {$3$};
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (1) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (3) -- (7);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
\index{leaf}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
The \key{leaves} of a tree are the nodes
|
2017-01-07 22:31:41 +01:00
|
|
|
with degree 1, i.e., with only one neighbor.
|
2017-02-17 21:13:30 +01:00
|
|
|
For example, the leaves of the above tree
|
2017-01-07 22:31:41 +01:00
|
|
|
are nodes 3, 5, 6 and 7.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
\index{root}
|
|
|
|
\index{rooted tree}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
In a \key{rooted} tree, one of the nodes
|
2017-02-05 12:40:54 +01:00
|
|
|
is appointed the \key{root} of the tree,
|
|
|
|
and all other nodes are
|
2017-01-07 22:31:41 +01:00
|
|
|
placed underneath the root.
|
|
|
|
For example, in the following tree,
|
|
|
|
node 1 is the root of the tree.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.9]
|
|
|
|
\node[draw, circle] (1) at (0,3) {$1$};
|
|
|
|
\node[draw, circle] (2) at (2,1) {$2$};
|
|
|
|
\node[draw, circle] (3) at (-2,1) {$4$};
|
|
|
|
\node[draw, circle] (4) at (0,1) {$5$};
|
|
|
|
\node[draw, circle] (5) at (2,-1) {$6$};
|
|
|
|
\node[draw, circle] (6) at (-3,-1) {$3$};
|
|
|
|
\node[draw, circle] (7) at (-1,-1) {$7$};
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (1) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (3) -- (7);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
\index{child}
|
|
|
|
\index{parent}
|
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
In a rooted tree, the \key{children} of a node
|
2017-01-07 22:31:41 +01:00
|
|
|
are its lower neighbors, and the \key{parent} of a node
|
|
|
|
is its upper neighbor.
|
|
|
|
Each node has exactly one parent,
|
2017-02-05 12:40:54 +01:00
|
|
|
except for the root that does not have a parent.
|
2017-01-07 22:31:41 +01:00
|
|
|
For example, in the above tree,
|
2017-02-17 21:13:30 +01:00
|
|
|
the children of node 4 are nodes 3 and 7,
|
2017-01-07 22:31:41 +01:00
|
|
|
and the parent is node 1.
|
|
|
|
|
|
|
|
\index{subtree}
|
|
|
|
|
|
|
|
The structure of a rooted tree is \emph{recursive}:
|
|
|
|
each node in the tree is the root of a \key{subtree}
|
|
|
|
that contains the node itself and all other nodes
|
2017-02-05 12:40:54 +01:00
|
|
|
that can be reached by traversing down the tree.
|
2017-01-07 22:31:41 +01:00
|
|
|
For example, in the above tree, the subtree of node 4
|
2017-02-05 12:40:54 +01:00
|
|
|
consists of nodes 4, 3 and 7.
|
2017-01-07 22:31:41 +01:00
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
\section{Tree traversal}
|
2017-01-07 22:31:41 +01:00
|
|
|
|
|
|
|
Depth-first search and breadth-first search
|
2017-02-05 12:40:54 +01:00
|
|
|
can be used for traversing the nodes in a tree.
|
2017-02-17 21:13:30 +01:00
|
|
|
The traversal of a tree is easier to implement than
|
|
|
|
that of a general graph, because
|
|
|
|
there are no cycles in the tree and it is not
|
2017-02-05 12:40:54 +01:00
|
|
|
possible to reach a node from multiple directions.
|
2017-01-07 22:31:41 +01:00
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
The typical way to traverse a tree is to start
|
|
|
|
a depth-first search at an arbitrary node.
|
|
|
|
The following recursive function can be used:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{lstlisting}
|
2017-01-07 22:31:41 +01:00
|
|
|
void dfs(int s, int e) {
|
|
|
|
// process node s
|
2016-12-28 23:54:51 +01:00
|
|
|
for (auto u : v[s]) {
|
2017-01-07 22:31:41 +01:00
|
|
|
if (u != e) dfs(u, s);
|
2016-12-28 23:54:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
\end{lstlisting}
|
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
The function parameters are the current node $s$
|
|
|
|
and the previous node $e$.
|
2017-02-05 12:40:54 +01:00
|
|
|
The purpose of the parameter $e$ is to make sure
|
|
|
|
that the search only moves to nodes
|
|
|
|
that have not been visited yet.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
The following function call starts the search
|
|
|
|
at node $x$:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{lstlisting}
|
2017-01-07 22:31:41 +01:00
|
|
|
dfs(x, 0);
|
2016-12-28 23:54:51 +01:00
|
|
|
\end{lstlisting}
|
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
In the first call $e=0$, because there is no
|
2017-01-07 22:31:41 +01:00
|
|
|
previous node, and it is allowed
|
|
|
|
to proceed to any direction in the tree.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
\subsubsection{Dynamic programming}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
Dynamic programming can be used to calculate
|
|
|
|
some information during a tree traversal.
|
2017-01-07 22:31:41 +01:00
|
|
|
Using dynamic programming, we can, for example,
|
2017-02-05 12:40:54 +01:00
|
|
|
calculate in $O(n)$ time for each node
|
|
|
|
in a rooted tree the
|
|
|
|
number of nodes in its subtree
|
|
|
|
or the length of the longest path from the node
|
|
|
|
to a leaf.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
As an example, let us calculate for each node $s$
|
2017-04-17 12:58:04 +02:00
|
|
|
a value $\texttt{count}[s]$: the number of nodes in its subtree.
|
2017-01-07 22:31:41 +01:00
|
|
|
The subtree contains the node itself and
|
|
|
|
all nodes in the subtrees of its children.
|
|
|
|
Thus, we can calculate the number of nodes
|
|
|
|
recursively using the following code:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{lstlisting}
|
2017-02-05 12:40:54 +01:00
|
|
|
void dfs(int s, int e) {
|
2017-04-17 12:58:04 +02:00
|
|
|
count[s] = 1;
|
2016-12-28 23:54:51 +01:00
|
|
|
for (auto u : v[s]) {
|
|
|
|
if (u == e) continue;
|
2017-02-05 12:40:54 +01:00
|
|
|
dfs(u, s);
|
2017-04-17 12:58:04 +02:00
|
|
|
count[s] += count[u];
|
2016-12-28 23:54:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
\end{lstlisting}
|
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
\section{Diameter}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
\index{diameter}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
The \key{diameter} of a tree
|
|
|
|
is the length of the longest path
|
|
|
|
between two nodes in the tree.
|
|
|
|
For example, in the tree
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.9]
|
|
|
|
\node[draw, circle] (1) at (0,3) {$1$};
|
|
|
|
\node[draw, circle] (2) at (2,3) {$2$};
|
|
|
|
\node[draw, circle] (3) at (0,1) {$4$};
|
|
|
|
\node[draw, circle] (4) at (2,1) {$5$};
|
|
|
|
\node[draw, circle] (5) at (4,1) {$6$};
|
|
|
|
\node[draw, circle] (6) at (-2,3) {$7$};
|
|
|
|
\node[draw, circle] (7) at (-2,1) {$3$};
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (1) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (3) -- (7);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
2017-01-07 22:31:41 +01:00
|
|
|
the diameter is 4, and it corresponds to two paths:
|
|
|
|
the path between nodes 3 and 6,
|
|
|
|
and the path between nodes 7 and 6.
|
|
|
|
|
|
|
|
Next we will learn two efficient algorithms
|
|
|
|
for calculating the diameter of a tree.
|
|
|
|
Both algorithms calculate the diameter in $O(n)$ time.
|
|
|
|
The first algorithm is based on dynamic programming,
|
|
|
|
and the second algorithm uses two depth-first searches
|
|
|
|
to calculate the diameter.
|
|
|
|
|
|
|
|
\subsubsection{Algorithm 1}
|
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
First, we root the tree arbitrarily.
|
|
|
|
After this, we use dynamic programming
|
|
|
|
to calculate for each node $x$
|
2017-01-07 22:31:41 +01:00
|
|
|
the length of the longest path that begins at some leaf,
|
2017-02-05 12:40:54 +01:00
|
|
|
ascends to $x$ and then descends to another leaf.
|
2017-01-07 22:31:41 +01:00
|
|
|
The length of the
|
|
|
|
longest such path equals the diameter of the tree.
|
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
In the example graph, the longest path begins at node 7,
|
2017-01-07 22:31:41 +01:00
|
|
|
ascends to node 1, and then descends to node 6:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.9]
|
|
|
|
\node[draw, circle] (1) at (0,3) {$1$};
|
|
|
|
\node[draw, circle] (2) at (2,1) {$2$};
|
|
|
|
\node[draw, circle] (3) at (-2,1) {$4$};
|
|
|
|
\node[draw, circle] (4) at (0,1) {$5$};
|
|
|
|
\node[draw, circle] (5) at (2,-1) {$6$};
|
|
|
|
\node[draw, circle] (6) at (-3,-1) {$3$};
|
|
|
|
\node[draw, circle] (7) at (-1,-1) {$7$};
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (1) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (3) -- (7);
|
|
|
|
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (7) -- (3);
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (3) -- (1);
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (1) -- (2);
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (2) -- (5);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
The algorithm first calculates for each node $x$
|
|
|
|
the length of the longest path from $x$ to a leaf.
|
2017-01-07 22:31:41 +01:00
|
|
|
For example, in the above tree,
|
2017-02-05 12:40:54 +01:00
|
|
|
the longest path from node 1 to a leaf has length 2
|
2017-01-07 22:31:41 +01:00
|
|
|
(the path can be $1 \rightarrow 4 \rightarrow 3$,
|
|
|
|
$1 \rightarrow 4 \rightarrow 7$ or $1 \rightarrow 2 \rightarrow 6$).
|
|
|
|
After this, the algorithm calculates for each node
|
2017-02-05 12:40:54 +01:00
|
|
|
$x$ the length of the longest path where $x$
|
2017-02-17 21:13:30 +01:00
|
|
|
is the highest point of the path.
|
2017-02-05 12:40:54 +01:00
|
|
|
The longest such path can be found by choosing
|
2017-02-17 21:13:30 +01:00
|
|
|
two children with longest paths to leaves.
|
2017-01-07 22:31:41 +01:00
|
|
|
For example, in the above graph,
|
2017-02-05 12:40:54 +01:00
|
|
|
nodes 2 and 4 yield the longest path for node 1.
|
2017-01-07 22:31:41 +01:00
|
|
|
|
|
|
|
\subsubsection{Algorithm 2}
|
|
|
|
|
|
|
|
Another efficient way to calculate the diameter
|
|
|
|
of a tree is based on two depth-first searches.
|
|
|
|
First, we choose an arbitrary node $a$ in the tree
|
2017-02-05 12:40:54 +01:00
|
|
|
and find the farthest node $b$ from $a$.
|
|
|
|
Then, we find the farthest node $c$ from $b$.
|
|
|
|
The diameter of the tree is the distance between $b$ and $c$.
|
2017-01-07 22:31:41 +01:00
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
In the example graph, $a$, $b$ and $c$ could be:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.9]
|
|
|
|
\node[draw, circle] (1) at (0,3) {$1$};
|
|
|
|
\node[draw, circle] (2) at (2,3) {$2$};
|
|
|
|
\node[draw, circle] (3) at (0,1) {$4$};
|
|
|
|
\node[draw, circle] (4) at (2,1) {$5$};
|
|
|
|
\node[draw, circle] (5) at (4,1) {$6$};
|
|
|
|
\node[draw, circle] (6) at (-2,3) {$7$};
|
|
|
|
\node[draw, circle] (7) at (-2,1) {$3$};
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (1) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (3) -- (7);
|
|
|
|
\node[color=red] at (2,1.6) {$a$};
|
|
|
|
\node[color=red] at (-1.4,3) {$b$};
|
|
|
|
\node[color=red] at (4,1.6) {$c$};
|
|
|
|
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (6) -- (3);
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (3) -- (1);
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (1) -- (2);
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (2) -- (5);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
This is an elegant method, but why does it work?
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
It helps to draw the tree differently so that
|
|
|
|
the path that corresponds to the diameter
|
|
|
|
is horizontal, and all other
|
|
|
|
nodes hang from it:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.9]
|
|
|
|
\node[draw, circle] (1) at (2,1) {$1$};
|
|
|
|
\node[draw, circle] (2) at (4,1) {$2$};
|
|
|
|
\node[draw, circle] (3) at (0,1) {$4$};
|
|
|
|
\node[draw, circle] (4) at (2,-1) {$5$};
|
|
|
|
\node[draw, circle] (5) at (6,1) {$6$};
|
|
|
|
\node[draw, circle] (6) at (0,-1) {$3$};
|
|
|
|
\node[draw, circle] (7) at (-2,1) {$7$};
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (1) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (3) -- (7);
|
|
|
|
\node[color=red] at (2,-1.6) {$a$};
|
|
|
|
\node[color=red] at (-2,1.6) {$b$};
|
|
|
|
\node[color=red] at (6,1.6) {$c$};
|
|
|
|
\node[color=red] at (2,1.6) {$x$};
|
|
|
|
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (7) -- (3);
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (3) -- (1);
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (1) -- (2);
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (2) -- (5);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
Node $x$ indicates the place where the path
|
|
|
|
from node $a$ joins the path that corresponds
|
|
|
|
to the diameter.
|
|
|
|
The farthest node from $a$
|
|
|
|
is node $b$, node $c$ or some other node
|
|
|
|
that is at least as far from node $x$.
|
2017-02-05 12:40:54 +01:00
|
|
|
Thus, this node is always a valid choice for
|
2017-01-07 22:31:41 +01:00
|
|
|
a starting node of a path that corresponds to the diameter.
|
|
|
|
|
|
|
|
\section{Distances between nodes}
|
|
|
|
|
|
|
|
A more difficult problem is to calculate
|
|
|
|
for each node in the tree and for each direction,
|
|
|
|
the maximum distance to a node in that direction.
|
|
|
|
It turns out that this can be calculated in
|
2017-02-05 12:40:54 +01:00
|
|
|
$O(n)$ time using dynamic programming.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{samepage}
|
2017-02-05 12:40:54 +01:00
|
|
|
In the example graph, the distances are as follows:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.9]
|
|
|
|
\node[draw, circle] (1) at (0,3) {$1$};
|
|
|
|
\node[draw, circle] (2) at (2,3) {$2$};
|
|
|
|
\node[draw, circle] (3) at (0,1) {$4$};
|
|
|
|
\node[draw, circle] (4) at (2,1) {$5$};
|
|
|
|
\node[draw, circle] (5) at (4,1) {$6$};
|
|
|
|
\node[draw, circle] (6) at (-2,3) {$7$};
|
|
|
|
\node[draw, circle] (7) at (-2,1) {$3$};
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (1) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (3) -- (7);
|
|
|
|
\node[color=red] at (0.5,3.2) {$2$};
|
|
|
|
\node[color=red] at (0.3,2.4) {$1$};
|
|
|
|
\node[color=red] at (-0.2,2.4) {$2$};
|
|
|
|
\node[color=red] at (-0.2,1.5) {$3$};
|
|
|
|
\node[color=red] at (-0.5,1.2) {$1$};
|
|
|
|
\node[color=red] at (-1.7,2.4) {$4$};
|
|
|
|
\node[color=red] at (-0.5,0.8) {$1$};
|
|
|
|
\node[color=red] at (-1.5,0.8) {$4$};
|
|
|
|
\node[color=red] at (1.5,3.2) {$3$};
|
|
|
|
\node[color=red] at (1.5,1.2) {$3$};
|
|
|
|
\node[color=red] at (3.5,1.2) {$4$};
|
|
|
|
\node[color=red] at (2.2,2.4) {$1$};
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
\end{samepage}
|
2017-02-05 12:40:54 +01:00
|
|
|
For example, the farthest node from node 4
|
2017-02-17 21:13:30 +01:00
|
|
|
in the direction of node 1 is node 6, and the distance to that
|
2017-01-07 22:31:41 +01:00
|
|
|
node is 3 using the path
|
|
|
|
$4 \rightarrow 1 \rightarrow 2 \rightarrow 6$.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{samepage}
|
2017-01-07 22:31:41 +01:00
|
|
|
Also in this problem, a good starting point
|
|
|
|
is to root the tree.
|
2017-02-05 12:40:54 +01:00
|
|
|
After this, all distances to leaves can
|
2017-01-07 22:31:41 +01:00
|
|
|
be calculated using dynamic programming:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.9]
|
|
|
|
\node[draw, circle] (1) at (0,3) {$1$};
|
|
|
|
\node[draw, circle] (2) at (2,1) {$2$};
|
|
|
|
\node[draw, circle] (3) at (-2,1) {$4$};
|
|
|
|
\node[draw, circle] (4) at (0,1) {$5$};
|
|
|
|
\node[draw, circle] (5) at (2,-1) {$6$};
|
|
|
|
\node[draw, circle] (6) at (-3,-1) {$3$};
|
|
|
|
\node[draw, circle] (7) at (-1,-1) {$7$};
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (1) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (3) -- (7);
|
|
|
|
|
|
|
|
\node[color=red] at (-2.5,0.7) {$1$};
|
|
|
|
\node[color=red] at (-1.5,0.7) {$1$};
|
|
|
|
|
|
|
|
\node[color=red] at (2.2,0.5) {$1$};
|
|
|
|
|
|
|
|
\node[color=red] at (-0.5,2.8) {$2$};
|
|
|
|
\node[color=red] at (0.2,2.5) {$1$};
|
|
|
|
\node[color=red] at (0.5,2.8) {$2$};
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
\end{samepage}
|
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
The remaining task is to calculate
|
|
|
|
the distances through parents.
|
|
|
|
This can be done by traversing the tree once again
|
2017-01-07 22:31:41 +01:00
|
|
|
and keeping track of the largest distance from the parent
|
|
|
|
of the current node to some other node in another direction.
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
For example, the distance from node 2 upwards
|
|
|
|
is one larger than the distance from node 1
|
|
|
|
downwards in some other direction than node 2:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.9]
|
|
|
|
\node[draw, circle] (1) at (0,3) {$1$};
|
|
|
|
\node[draw, circle] (2) at (2,1) {$2$};
|
|
|
|
\node[draw, circle] (3) at (-2,1) {$4$};
|
|
|
|
\node[draw, circle] (4) at (0,1) {$5$};
|
|
|
|
\node[draw, circle] (5) at (2,-1) {$6$};
|
|
|
|
\node[draw, circle] (6) at (-3,-1) {$3$};
|
|
|
|
\node[draw, circle] (7) at (-1,-1) {$7$};
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (1) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (3) -- (7);
|
|
|
|
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (1) -- (2);
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (1) -- (3);
|
|
|
|
\path[draw,thick,-,color=red,line width=2pt] (3) -- (7);
|
|
|
|
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
2017-01-07 22:31:41 +01:00
|
|
|
Finally, we can calculate the distances for all nodes
|
|
|
|
and all directions:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.9]
|
|
|
|
\node[draw, circle] (1) at (0,3) {$1$};
|
|
|
|
\node[draw, circle] (2) at (2,1) {$2$};
|
|
|
|
\node[draw, circle] (3) at (-2,1) {$4$};
|
|
|
|
\node[draw, circle] (4) at (0,1) {$5$};
|
|
|
|
\node[draw, circle] (5) at (2,-1) {$6$};
|
|
|
|
\node[draw, circle] (6) at (-3,-1) {$3$};
|
|
|
|
\node[draw, circle] (7) at (-1,-1) {$7$};
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (1) -- (3);
|
|
|
|
\path[draw,thick,-] (1) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (3) -- (6);
|
|
|
|
\path[draw,thick,-] (3) -- (7);
|
|
|
|
|
|
|
|
\node[color=red] at (-2.5,0.7) {$1$};
|
|
|
|
\node[color=red] at (-1.5,0.7) {$1$};
|
|
|
|
|
|
|
|
\node[color=red] at (2.2,0.5) {$1$};
|
|
|
|
|
|
|
|
\node[color=red] at (-0.5,2.8) {$2$};
|
|
|
|
\node[color=red] at (0.2,2.5) {$1$};
|
|
|
|
\node[color=red] at (0.5,2.8) {$2$};
|
|
|
|
|
|
|
|
\node[color=red] at (-3,-0.4) {$4$};
|
|
|
|
\node[color=red] at (-1,-0.4) {$4$};
|
|
|
|
\node[color=red] at (-2,1.6) {$3$};
|
|
|
|
\node[color=red] at (2,1.6) {$3$};
|
|
|
|
|
|
|
|
\node[color=red] at (2.2,-0.4) {$4$};
|
|
|
|
\node[color=red] at (0.2,1.6) {$3$};
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
\section{Binary trees}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
\index{binary tree}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{samepage}
|
2017-01-07 22:31:41 +01:00
|
|
|
A \key{binary tree} is a rooted tree
|
2017-02-05 12:40:54 +01:00
|
|
|
where each node has a left and right subtree.
|
2017-01-07 22:31:41 +01:00
|
|
|
It is possible that a subtree of a node is empty.
|
|
|
|
Thus, every node in a binary tree has
|
2017-02-05 12:40:54 +01:00
|
|
|
zero, one or two children.
|
2017-01-07 22:31:41 +01:00
|
|
|
|
|
|
|
For example, the following tree is a binary tree:
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.9]
|
|
|
|
\node[draw, circle] (1) at (0,0) {$1$};
|
|
|
|
\node[draw, circle] (2) at (-1.5,-1.5) {$2$};
|
|
|
|
\node[draw, circle] (3) at (1.5,-1.5) {$3$};
|
|
|
|
\node[draw, circle] (4) at (-3,-3) {$4$};
|
|
|
|
\node[draw, circle] (5) at (0,-3) {$5$};
|
|
|
|
\node[draw, circle] (6) at (-1.5,-4.5) {$6$};
|
|
|
|
\node[draw, circle] (7) at (3,-3) {$7$};
|
|
|
|
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
\path[draw,thick,-] (1) -- (3);
|
|
|
|
\path[draw,thick,-] (2) -- (4);
|
|
|
|
\path[draw,thick,-] (2) -- (5);
|
|
|
|
\path[draw,thick,-] (5) -- (6);
|
|
|
|
\path[draw,thick,-] (3) -- (7);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
|
|
|
\end{samepage}
|
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
\index{pre-order}
|
|
|
|
\index{in-order}
|
|
|
|
\index{post-order}
|
2016-12-28 23:54:51 +01:00
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
The nodes in a binary tree have three natural
|
2017-02-05 12:40:54 +01:00
|
|
|
orderings that correspond to different ways to
|
2017-02-17 21:13:30 +01:00
|
|
|
recursively traverse the tree:
|
2016-12-28 23:54:51 +01:00
|
|
|
|
|
|
|
\begin{itemize}
|
2017-01-07 22:31:41 +01:00
|
|
|
\item \key{pre-order}: first process the root,
|
|
|
|
then traverse the left subtree, then traverse the right subtree
|
|
|
|
\item \key{in-order}: first traverse the left subtree,
|
|
|
|
then process the root, then traverse the right subtree
|
|
|
|
\item \key{post-order}: first traverse the left subtree,
|
|
|
|
then traverse the right subtree, then process the root
|
2016-12-28 23:54:51 +01:00
|
|
|
\end{itemize}
|
|
|
|
|
2017-01-07 22:31:41 +01:00
|
|
|
For the above tree, the nodes in
|
|
|
|
pre-order are
|
2016-12-28 23:54:51 +01:00
|
|
|
$[1,2,4,5,6,3,7]$,
|
2017-01-07 22:31:41 +01:00
|
|
|
in in-order $[4,2,6,5,1,3,7]$
|
|
|
|
and in post-order $[4,6,5,2,7,3,1]$.
|
|
|
|
|
2017-02-05 12:40:54 +01:00
|
|
|
If we know the pre-order and in-order
|
|
|
|
of a tree, we can reconstruct the exact structure of the tree.
|
2017-02-17 21:13:30 +01:00
|
|
|
For example, the above tree is the only possible tree
|
2017-01-07 22:31:41 +01:00
|
|
|
with pre-order $[1,2,4,5,6,3,7]$ and
|
|
|
|
in-order $[4,2,6,5,1,3,7]$.
|
2017-02-05 12:40:54 +01:00
|
|
|
In a similar way, the post-order and in-order
|
2017-01-07 22:31:41 +01:00
|
|
|
also determine the structure of a tree.
|
|
|
|
|
|
|
|
However, the situation is different if we only know
|
2017-02-05 12:40:54 +01:00
|
|
|
the pre-order and post-order of a tree.
|
2017-01-07 22:31:41 +01:00
|
|
|
In this case, there may be more than one tree
|
2017-02-05 12:40:54 +01:00
|
|
|
that match the orderings.
|
2017-01-07 22:31:41 +01:00
|
|
|
For example, in both of the trees
|
2016-12-28 23:54:51 +01:00
|
|
|
\begin{center}
|
|
|
|
\begin{tikzpicture}[scale=0.9]
|
|
|
|
\node[draw, circle] (1) at (0,0) {$1$};
|
|
|
|
\node[draw, circle] (2) at (-1.5,-1.5) {$2$};
|
|
|
|
\path[draw,thick,-] (1) -- (2);
|
|
|
|
|
|
|
|
\node[draw, circle] (1b) at (0+4,0) {$1$};
|
|
|
|
\node[draw, circle] (2b) at (1.5+4,-1.5) {$2$};
|
|
|
|
\path[draw,thick,-] (1b) -- (2b);
|
|
|
|
\end{tikzpicture}
|
|
|
|
\end{center}
|
2017-02-05 12:40:54 +01:00
|
|
|
the pre-order is $[1,2]$ and the post-order is $[2,1]$,
|
|
|
|
but the structures of the trees are different.
|
2016-12-28 23:54:51 +01:00
|
|
|
|