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
property is not necessary.
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.
It is often easier to design an offline algorithm
compared to an online algorithm.
@ -1138,9 +1138,119 @@ when $a$ and $b$ are C++ standard library data structures.
\subsubsection{Lowest common ancestors}
It turns out that we can also process a collection of
lowest common ancestor queries using an offline algorithm\footnote{This
algorithm was discovered by R. E. Tarjan in 1979 \cite{tar79}.}.
This algorithm is based on the union-find data structure
(see 15.2), and it is easier to implement than the
previous algorithms presented in this chapter.
There is also an offline algorithm
for processing a set of
lowest common ancestor queries\footnote{This
algorithm was published by R. E. Tarjan in 1979 \cite{tar79}.}.
The algorithm is based on the union-find data structure
(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.
\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}
R. E. Tarjan and U. Vishkin.
Finding biconnected componemts and computing tree functions in logarithmic parallel time.