Add Tarjan's algorithm

This commit is contained in:
Antti H S Laaksonen 2017-05-07 00:29:34 +03:00
parent 479a6bc2f9
commit c1154d9147
2 changed files with 122 additions and 7 deletions

View File

@ -939,7 +939,7 @@ processes each query before receiving the next query.
However, in many problems, the online However, in many problems, the online
property is not necessary. property is not necessary.
In this section, we focus on \emph{offline} algorithms In this section, we focus on \emph{offline} algorithms
that are given a collection of queries that can be that are given a set of queries that can be
processed in any order. processed in any order.
It is often easier to design an offline algorithm It is often easier to design an offline algorithm
compared to an online algorithm. compared to an online algorithm.
@ -1138,9 +1138,119 @@ when $a$ and $b$ are C++ standard library data structures.
\subsubsection{Lowest common ancestors} \subsubsection{Lowest common ancestors}
It turns out that we can also process a collection of There is also an offline algorithm
lowest common ancestor queries using an offline algorithm\footnote{This for processing a set of
algorithm was discovered by R. E. Tarjan in 1979 \cite{tar79}.}. lowest common ancestor queries\footnote{This
This algorithm is based on the union-find data structure algorithm was published by R. E. Tarjan in 1979 \cite{tar79}.}.
(see 15.2), and it is easier to implement than the The algorithm is based on the union-find data structure
previous algorithms presented in this chapter. (see Chapter 15.2), and the benefit of the algorithm is
that it is easier to implement than the
algorithms discussed earlier in this chapter.
The algorithm is given as input a set of pairs of nodes,
and it determines for each such pair the
lowest common ancestor.
The algorithm performs a depth-first tree traversal
and maintains disjoint sets of nodes.
Initially, each node belongs to a separate set.
For each set, we also maintain the highest node in the
tree that belongs to the set.
When the algorithm visits a node $x$,
it goes through all nodes $y$ such that
the lowest common ancestor of $x$ and $y$
has to be found.
If $y$ has already been visited,
the algorithm reports that the
lowest common ancestor of $x$ and $y$
is the highest node in the set of $y$.
Then, after processing the subtree of $x$,
the algorithm combines the sets of $x$ and its parent.
For example, assume that we would like the lowest
common ancestor of node pairs $(5,8)$
and $(2,7)$ in the following tree:
\begin{center}
\begin{tikzpicture}[scale=0.85]
\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] (5) at (2,-1) {$7$};
\node[draw, circle] (6) at (-3,-1) {$5$};
\node[draw, circle] (7) at (-1,-1) {$6$};
\node[draw, circle] (8) at (-1,-3) {$8$};
\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,-] (7) -- (8);
\end{tikzpicture}
\end{center}
In the following pictures, gray nodes denote visited nodes
and dashed groups of nodes belong to the same set.
When the algorithm visits node 8, it notices that
node 5 has been visited and the highest node
in its set is 2. Thus, the lowest common ancestor
of nodes 5 and 8 is 2:
\begin{center}
\begin{tikzpicture}[scale=0.85]
\node[draw, circle, fill=lightgray] (1) at (0,3) {$1$};
\node[draw, circle] (2) at (2,1) {$4$};
\node[draw, circle, fill=lightgray] (3) at (-2,1) {$2$};
\node[draw, circle] (4) at (0,1) {$3$};
\node[draw, circle] (5) at (2,-1) {$7$};
\node[draw, circle, fill=lightgray] (6) at (-3,-1) {$5$};
\node[draw, circle, fill=lightgray] (7) at (-1,-1) {$6$};
\node[draw, circle, fill=gray] (8) at (-1,-3) {$8$};
\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,-] (7) -- (8);
\draw [red,thick,dashed,line width=2pt,rotate around={-28:(-2,0)}] (-2.9,1.5) rectangle (-1.9,-2);
\draw [red,thick,dashed,line width=2pt] (-1.5,-0.5) rectangle (-0.5,-1.5);
\draw [red,thick,dashed,line width=2pt] (-1.5,-2.5) rectangle (-0.5,-3.5);
\draw [red,thick,dashed,line width=2pt] (0.5,3.5) rectangle (-0.5,2.5);
\draw [red,thick,dashed,line width=2pt] (0.5,1.5) rectangle (-0.5,0.5);
\draw [red,thick,dashed,line width=2pt] (2.5,1.5) rectangle (1.5,0.5);
\draw [red,thick,dashed,line width=2pt] (2.5,-0.5) rectangle (1.5,-1.5);
\end{tikzpicture}
\end{center}
Later, when visiting node 7,
the algorithm determines that
the lowest common ancestor of nodes 2 and 7 is 1:
\begin{center}
\begin{tikzpicture}[scale=0.85]
\node[draw, circle, fill=lightgray] (1) at (0,3) {$1$};
\node[draw, circle, fill=lightgray] (2) at (2,1) {$4$};
\node[draw, circle, fill=lightgray] (3) at (-2,1) {$2$};
\node[draw, circle, fill=lightgray] (4) at (0,1) {$3$};
\node[draw, circle, fill=gray] (5) at (2,-1) {$7$};
\node[draw, circle, fill=lightgray] (6) at (-3,-1) {$5$};
\node[draw, circle, fill=lightgray] (7) at (-1,-1) {$6$};
\node[draw, circle, fill=lightgray] (8) at (-1,-3) {$8$};
\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,-] (7) -- (8);
\draw [red,thick,dashed,line width=2pt] (0.5,3.5) rectangle (-3.5,-3.5);
\draw [red,thick,dashed,line width=2pt] (2.5,1.5) rectangle (1.5,0.5);
\draw [red,thick,dashed,line width=2pt] (2.5,-0.5) rectangle (1.5,-1.5);
\end{tikzpicture}
\end{center}

View File

@ -352,6 +352,11 @@
Efficiency of a good but not linear set union algorithm. Efficiency of a good but not linear set union algorithm.
\emph{Journal of the ACM}, 22(2):215--225, 1975. \emph{Journal of the ACM}, 22(2):215--225, 1975.
\bibitem{tar79}
R. E. Tarjan.
Applications of path compression on balanced trees.
\emph{Journal of the ACM}, 26(4):690--715, 1979.
\bibitem{tar84} \bibitem{tar84}
R. E. Tarjan and U. Vishkin. R. E. Tarjan and U. Vishkin.
Finding biconnected componemts and computing tree functions in logarithmic parallel time. Finding biconnected componemts and computing tree functions in logarithmic parallel time.