Skip to content

Commit

Permalink
binary trees
Browse files Browse the repository at this point in the history
  • Loading branch information
emanuele-em committed Oct 30, 2023
1 parent 087f14a commit af66a3d
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@
- [Tree algorithms](tree_algorithm.md)
- [Tree traversal](tree_traversal.md)
- [Diameter](diameter.md)
<!-- - [All longest paths](README.md) -->
<!-- - [Binary trees](README.md) -->
- [All longest paths](all_longest_paths.md)
- [Binary trees](binary_trees.md)
<!-- - [Spanning trees](README.md) -->
<!-- - [Kruskal’s algorithm](README.md) -->
<!-- - [Union-find structure](README.md) -->
Expand Down
156 changes: 156 additions & 0 deletions src/all_longest_paths.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# All longest paths

Our next problem is to calculate for every node
in the tree the maximum length of a path
that begins at the node.
This can be seen as a generalization of the
tree diameter problem, because the largest of those
lengths equals the diameter of the tree.
Also this problem can be solved in $O(n)$ time.

As an example, consider the following tree:

<script type="text/tikz">
\begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (0,0) {1};
\node[draw, circle] (2) at (-1.5,-1) {4};
\node[draw, circle] (3) at (2,0) {2};
\node[draw, circle] (4) at (-1.5,1) {3};
\node[draw, circle] (6) at (3.5,-1) {6};
\node[draw, circle] (7) at (3.5,1) {5};
\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (1) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (3) -- (6);
\path[draw,thick,-] (3) -- (7);
\end{tikzpicture}
</script>

Let `maxLength(x)` denote the maximum length
of a path that begins at node $x$.
For example, in the above tree,
`maxLength(4)=3`, because there
is a path $4 \rightarrow 1 \rightarrow 2 \rightarrow 6$.
Here is a complete table of the values:

| | | | | | | |
|-|-|-|-|-|-|-|
| node $x$ | 1 | 2 | 3 | 4 | 5 | 6 |
| maxLength($x$) | 2 | 2 | 3 | 3 | 3 | 3 |

Also in this problem, a good starting point
for solving the problem is to root the tree arbitrarily:

<script type="text/tikz">
\begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (0,3) {1};
\node[draw, circle] (2) at (2,1) {4};
\node[draw, circle] (3) at (-2,1) {2};
\node[draw, circle] (4) at (0,1) {3};
\node[draw, circle] (6) at (-3,-1) {5};
\node[draw, circle] (7) at (-1,-1) {6};
\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (1) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (3) -- (6);
\path[draw,thick,-] (3) -- (7);
\end{tikzpicture}
</script>

The first part of the problem is to calculate for every node $x$
the maximum length of a path that goes through a child of $x$.
For example, the longest path from node 1
goes through its child 2:

<script type="text/tikz">
\begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (0,3) {1};
\node[draw, circle] (2) at (2,1) {4};
\node[draw, circle] (3) at (-2,1) {2};
\node[draw, circle] (4) at (0,1) {3};
\node[draw, circle] (6) at (-3,-1) {5};
\node[draw, circle] (7) at (-1,-1) {6};
\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (1) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (3) -- (6);
\path[draw,thick,-] (3) -- (7);

\path[draw,thick,->,color=red,line width=2pt] (1) -- (3);
\path[draw,thick,->,color=red,line width=2pt] (3) -- (6);
\end{tikzpicture}
</script>

This part is easy to solve in $O(n)$ time, because we can use
dynamic programming as we have done previously.

Then, the second part of the problem is to calculate
for every node $x$ the maximum length of a path
through its parent $p$.
For example, the longest path
from node 3 goes through its parent 1:

<script type="text/tikz">
\begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (0,3) {1};
\node[draw, circle] (2) at (2,1) {4};
\node[draw, circle] (3) at (-2,1) {2};
\node[draw, circle] (4) at (0,1) {3};
\node[draw, circle] (6) at (-3,-1) {5};
\node[draw, circle] (7) at (-1,-1) {6};
\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (1) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (3) -- (6);
\path[draw,thick,-] (3) -- (7);

\path[draw,thick,->,color=red,line width=2pt] (4) -- (1);
\path[draw,thick,->,color=red,line width=2pt] (1) -- (3);
\path[draw,thick,->,color=red,line width=2pt] (3) -- (6);
\end{tikzpicture}
</script>

At first glance, it seems that we should choose
the longest path from $p$.
However, this _does not_ always work,
because the longest path from $p$
may go through $x$.
Here is an example of this situation:

<script type="text/tikz">
\begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (0,3) {1};
\node[draw, circle] (2) at (2,1) {4};
\node[draw, circle] (3) at (-2,1) {2};
\node[draw, circle] (4) at (0,1) {3};
\node[draw, circle] (6) at (-3,-1) {5};
\node[draw, circle] (7) at (-1,-1) {6};
\path[draw,thick,-] (1) -- (2);
\path[draw,thick,-] (1) -- (3);
\path[draw,thick,-] (1) -- (4);
\path[draw,thick,-] (3) -- (6);
\path[draw,thick,-] (3) -- (7);

\path[draw,thick,->,color=red,line width=2pt] (3) -- (1);
\path[draw,thick,->,color=red,line width=2pt] (1) -- (2);
\end{tikzpicture}
</script>

Still, we can solve the second part in
$O(n)$ time by storing _two_ maximum lengths
for each node $x$:

- `maxLength_1(x)`: the maximum length of a path from $x$
- `maxLength_2(x)`: the maximum length of a path from $x$ in another direction than the first path

For example, in the above graph,
`maxLength_1(1)=2` using the path $1 \rightarrow 2 \rightarrow 5$,
and `maxLength_2(1)=1` using the path $1 \rightarrow 3$.

Finally, if the path that corresponds to
`maxLength_1(p)` goes through $x$,
we conclude that the maximum length is
`maxLength_2(p)+1`,
and otherwise the maximum length is
`maxLength_1(p)+1`.

75 changes: 75 additions & 0 deletions src/binary_trees.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Binary trees

A **binary tree** is a rooted tree
where each node has a left and right subtree.
It is possible that a subtree of a node is empty.
Thus, every node in a binary tree has
zero, one or two children.

For example, the following tree is a binary tree:

<script type="text/tikz">
\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}
</script>

The nodes of a binary tree have three natural
orderings that correspond to different ways to
recursively traverse the tree:

- **pre-order**: first process the root,
then traverse the left subtree, then traverse the right subtree
- **in-order**: first traverse the left subtree,
then process the root, then traverse the right subtree
- **post-order**: first traverse the left subtree,
then traverse the right subtree, then process the root

For the above tree, the nodes in
pre-order are
\\([1,2,4,5,6,3,7]\\),
in in-order \\([4,2,6,5,1,3,7]\\)
and in post-order \\([4,6,5,2,7,3,1]\\).

If we know the pre-order and in-order
of a tree, we can reconstruct the exact structure of the tree.
For example, the above tree is the only possible tree
with pre-order \\([1,2,4,5,6,3,7]\\) and
in-order \\([4,2,6,5,1,3,7]\\).
In a similar way, the post-order and in-order
also determine the structure of a tree.

However, the situation is different if we only know
the pre-order and post-order of a tree.
In this case, there may be more than one tree
that match the orderings.
For example, in both of the trees

<script type="text/tikz">
\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}
</script>

the pre-order is \\([1, 2]\\) and the post-order is \\([2, 1]\\), but the structures of the trees are different


0 comments on commit af66a3d

Please sign in to comment.