From c447a6f33b2ccab91a4c2197fb95bd970ccfb966 Mon Sep 17 00:00:00 2001 From: Antti H S Laaksonen Date: Fri, 17 Feb 2017 22:13:30 +0200 Subject: [PATCH] Corrections --- luku11.tex | 127 +++++++++++++++++++++++++++++++++++------------------ luku12.tex | 40 ++++++++++++----- luku13.tex | 74 +++++++++++++++---------------- luku14.tex | 22 +++++----- luku15.tex | 46 +++++++++---------- 5 files changed, 186 insertions(+), 123 deletions(-) diff --git a/luku11.tex b/luku11.tex index d255972..110e2f4 100644 --- a/luku11.tex +++ b/luku11.tex @@ -1,12 +1,12 @@ \chapter{Basics of graphs} Many programming problems can be solved by -modelling the problem as a graph problem +modeling the problem as a graph problem and using an appropriate graph algorithm. A typical example of a graph is a network of roads and cities in a country. Sometimes, though, the graph is hidden -in the problem and it can be difficult to detect it. +in the problem and it may be difficult to detect it. This part of the book discusses graph algorithms, especially focusing on topics that @@ -15,7 +15,7 @@ In this chapter, we go through concepts related to graphs, and study different ways to represent graphs in algorithms. -\section{Terminology} +\section{Graph terminology} \index{graph} \index{node} @@ -56,17 +56,51 @@ A \key{path} leads from node $a$ to node $b$ through edges of the graph. The \key{length} of a path is the number of edges in it. -For example, in the above graph, there -are several paths from node 1 to node 5: +For example, the above graph contains +the path $1 \rightarrow 3 \rightarrow 4 \rightarrow 5$ +from node 1 to node 5: -\begin{itemize} -\item $1 \rightarrow 2 \rightarrow 5$ (length 2) -\item $1 \rightarrow 4 \rightarrow 5$ (length 2) -\item $1 \rightarrow 2 \rightarrow 4 \rightarrow 5$ (length 3) -\item $1 \rightarrow 3 \rightarrow 4 \rightarrow 5$ (length 3) -\item $1 \rightarrow 4 \rightarrow 2 \rightarrow 5$ (length 3) -\item $1 \rightarrow 3 \rightarrow 4 \rightarrow 2 \rightarrow 5$ (length 4) -\end{itemize} +\begin{center} +\begin{tikzpicture}[scale=0.9] +\node[draw, circle] (1) at (1,3) {$1$}; +\node[draw, circle] (2) at (4,3) {$2$}; +\node[draw, circle] (3) at (1,1) {$3$}; +\node[draw, circle] (4) at (4,1) {$4$}; +\node[draw, circle] (5) at (6,2) {$5$}; + +\path[draw,thick,-] (1) -- (2); +\path[draw,thick,-] (1) -- (3); +\path[draw,thick,-] (1) -- (4); +\path[draw,thick,-] (3) -- (4); +\path[draw,thick,-] (2) -- (4); +\path[draw,thick,-] (2) -- (5); +\path[draw,thick,-] (4) -- (5); + +\path[draw=red,thick,->,line width=2pt] (1) -- (3); +\path[draw=red,thick,->,line width=2pt] (3) -- (4); +\path[draw=red,thick,->,line width=2pt] (4) -- (5); +\end{tikzpicture} +\end{center} + +\index{cycle} + +A path is a \key{cycle} if the first and last +node is the same. +For example, the above graph contains +the cycle $1 \rightarrow 3 \rightarrow 4 \rightarrow 1$. +A path is \key{simple} if each node appears +at most once in the path. + + +% +% \begin{itemize} +% \item $1 \rightarrow 2 \rightarrow 5$ (length 2) +% \item $1 \rightarrow 4 \rightarrow 5$ (length 2) +% \item $1 \rightarrow 2 \rightarrow 4 \rightarrow 5$ (length 3) +% \item $1 \rightarrow 3 \rightarrow 4 \rightarrow 5$ (length 3) +% \item $1 \rightarrow 4 \rightarrow 2 \rightarrow 5$ (length 3) +% \item $1 \rightarrow 3 \rightarrow 4 \rightarrow 2 \rightarrow 5$ (length 4) +% \end{itemize} \subsubsection{Connectivity} @@ -185,29 +219,18 @@ For example, the following graph is directed: \end{tikzpicture} \end{center} -The above graph contains a path from -node $3$ to node $5$ through the edges -$3 \rightarrow 1 \rightarrow 2 \rightarrow 5$, +The above graph contains +the path $3 \rightarrow 1 \rightarrow 2 \rightarrow 5$ +from node $3$ to node $5$, but there is no path from node $5$ to node $3$. -\index{cycle} -\index{acyclic graph} - -A \key{cycle} is a path whose first and -last node is the same. -For example, the above graph contains -a cycle -$1 \rightarrow 2 \rightarrow 4 \rightarrow 1$. -If a graph does not contain any cycles, -it is called \key{acyclic}. - \subsubsection{Edge weights} \index{weighted graph} In a \key{weighted} graph, each edge is assigned a \key{weight}. -Often, the weights are interpreted as edge lengths. +Often the weights are interpreted as edge lengths. For example, the following graph is weighted: \begin{center} \begin{tikzpicture}[scale=0.9] @@ -268,7 +291,7 @@ so its degree is 3. The sum of degrees in a graph is always $2m$, where $m$ is the number of edges, because each edge -increases the degree of two nodes by one. +increases the degree of exactly two nodes by one. For this reason, the sum of degrees is always even. \index{regular graph} @@ -358,7 +381,7 @@ is bipartite, because it can be colored as follows: \path[draw,thick,-] (5) -- (6); \end{tikzpicture} \end{center} -However, the following graph is not bipartite: +However, the graph \begin{center} \begin{tikzpicture}[scale=0.9] \node[draw, circle] (1) at (1,3) {$2$}; @@ -376,6 +399,29 @@ However, the following graph is not bipartite: \path[draw,thick,-] (1) -- (6); \end{tikzpicture} \end{center} +is not bipartite, because it is not possible to color +the following cycle of three nodes using two colors: +\begin{center} +\begin{tikzpicture}[scale=0.9] +\node[draw, circle] (1) at (1,3) {$2$}; +\node[draw, circle] (2) at (4,3) {$3$}; +\node[draw, circle] (3) at (1,1) {$5$}; +\node[draw, circle] (4) at (4,1) {$6$}; +\node[draw, circle] (5) at (-2,1) {$4$}; +\node[draw, circle] (6) at (-2,3) {$1$}; +\path[draw,thick,-] (1) -- (2); +\path[draw,thick,-] (1) -- (3); +\path[draw,thick,-] (3) -- (4); +\path[draw,thick,-] (2) -- (4); +\path[draw,thick,-] (3) -- (6); +\path[draw,thick,-] (5) -- (6); +\path[draw,thick,-] (1) -- (6); + +\path[draw=red,thick,-,line width=2pt] (1) -- (3); +\path[draw=red,thick,-,line width=2pt] (3) -- (6); +\path[draw=red,thick,-,line width=2pt] (6) -- (1); +\end{tikzpicture} +\end{center} \subsubsection{Simplicity} @@ -386,7 +432,7 @@ if no edge starts and ends at the same node, and there are no multiple edges between two nodes. Often we assume that graphs are simple. -For example, the graph +For example, the following graph is \emph{not} simple: \begin{center} \begin{tikzpicture}[scale=0.9] \node[draw, circle] (1) at (1,3) {$2$}; @@ -409,9 +455,6 @@ For example, the graph \path[draw,thick,-] (5) edge [loop left] (5); \end{tikzpicture} \end{center} -is \emph{not} simple, because there is an edge that starts -and ends at node 4, and there are two edges -between nodes 2 and 3. \section{Graph representation} @@ -420,7 +463,7 @@ in algorithms. The choice of a data structure depends on the size of the graph and the way the algorithm processes it. -Next we will go through three possible representations. +Next we will go through three common representations. \subsubsection{Adjacency list representation} @@ -431,7 +474,7 @@ each node $x$ in the graph is assigned an \key{adjacency list} that consists of nodes to which there is an edge from $x$. Adjacency lists are the most popular -way to represent a graph, and most algorithms can be +way to represent graphs, and most algorithms can be efficiently implemented using them. A convenient way to store the adjacency lists is to declare @@ -440,8 +483,8 @@ an array of vectors as follows: vector v[N]; \end{lstlisting} -The constant $N$ is chosen so that there -is space for all adjacency lists. +The constant $N$ is chosen so that all +adjacency lists can be stored. For example, the graph \begin{center} @@ -468,7 +511,7 @@ v[4].push_back(1); \end{lstlisting} If the graph is undirected, it can be stored in a similar way, -but each edge is stored in both directions. +but each edge is added in both directions. For a weighted graph, the structure can be extended as follows: @@ -507,7 +550,7 @@ v[4].push_back({1,2}); The benefit in using adjacency lists is that we can efficiently find the nodes to which -we can move from a certain node through an edge. +we can move from a given node through an edge. For example, the following loop goes through all nodes to which we can move from node $s$: @@ -522,7 +565,7 @@ for (auto u : v[s]) { \index{adjacency matrix} An \key{adjacency matrix} is a two-dimensional array -that indicates which edges exist in the graph. +that indicates which edges the graph contains. We can efficiently check from an adjacency matrix if there is an edge between two nodes. The matrix can be stored as an array @@ -647,7 +690,7 @@ if the graph is large. An \key{edge list} contains all edges of a graph in some order. This is a convenient way to represent a graph -if the algorithm processes all edges of the graph, +if the algorithm processes all edges of the graph and it is not needed to find edges that start at a given node. diff --git a/luku12.tex b/luku12.tex index 2679627..fe77bac 100644 --- a/luku12.tex +++ b/luku12.tex @@ -48,9 +48,8 @@ the following graph: \path[draw,thick,-] (2) -- (5); \end{tikzpicture} \end{center} -The algorithm can begin at any node in the graph, -but we will now assume that it begins -at node 1. +We may begin the search at any node in the graph, +but we will now begin the search at node 1. The search first proceeds to node 2: \begin{center} @@ -305,7 +304,7 @@ to implement than depth-first search, because the algorithm visits nodes in different parts of the graph. A typical implementation is based on -a queue of nodes to be processed. +a queue that contains nodes. At each step, the next node in the queue will be processed. @@ -329,7 +328,7 @@ int z[N], e[N]; so that the array \texttt{z} indicates which nodes the search has already visited and the array \texttt{e} will contain the -minimum distance to all nodes in the graph. +distances to all nodes in the graph. The search can be implemented as follows: \begin{lstlisting} z[s] = 1; e[x] = 0; @@ -364,7 +363,7 @@ assume that the graph is undirected. A graph is connected if there is a path between any two nodes in the graph. Thus, we can check if a graph is connected -by selecting an arbitrary node and +by choosing an arbitrary node and finding out if we can reach all other nodes. For example, in the graph @@ -406,7 +405,7 @@ the following nodes: Since the search did not visit all the nodes, we can conclude that the graph is not connected. In a similar way, we can also find all connected components -of a graph by iterating trough the nodes and always +of a graph by iterating through the nodes and always starting a new depth-first search if the current node does not belong to any component yet. @@ -421,6 +420,24 @@ visited. For example, the graph \begin{center} \begin{tikzpicture} +\node[draw, circle] (2) at (7,5) {$2$}; +\node[draw, circle] (1) at (3,5) {$1$}; +\node[draw, circle] (3) at (5,4) {$3$}; +\node[draw, circle] (5) at (7,3) {$5$}; +\node[draw, circle] (4) at (3,3) {$4$}; + +\path[draw,thick,-] (1) -- (3); +\path[draw,thick,-] (1) -- (4); +\path[draw,thick,-] (3) -- (4); +\path[draw,thick,-] (2) -- (5); +\path[draw,thick,-] (2) -- (3); +\path[draw,thick,-] (3) -- (5); +\end{tikzpicture} +\end{center} +contains two cycles and we can find one +of them as follows: +\begin{center} +\begin{tikzpicture} \node[draw, circle,fill=lightgray] (2) at (7,5) {$2$}; \node[draw, circle,fill=lightgray] (1) at (3,5) {$1$}; \node[draw, circle,fill=lightgray] (3) at (5,4) {$3$}; @@ -440,7 +457,7 @@ For example, the graph \end{tikzpicture} \end{center} -contains a cycle because when we move from +When we move from node 2 to node 5 it turns out that the neighbor 3 has already been visited. Thus, the graph contains a cycle that goes through node 3, @@ -450,7 +467,8 @@ Another way to find out whether a graph contains a cycle is to simply calculate the number of nodes and edges in every component. If a component contains $c$ nodes and no cycle, -it must contain exactly $c-1$ edges. +it must contain exactly $c-1$ edges +(so it has to be a tree). If there are $c$ or more edges, the component surely contains a cycle. @@ -489,7 +507,7 @@ For example, the graph \path[draw,thick,-] (5) -- (3); \end{tikzpicture} \end{center} -is not bipartite because a search from node 1 +is not bipartite, because a search from node 1 proceeds as follows: \begin{center} \begin{tikzpicture} @@ -512,7 +530,7 @@ proceeds as follows: \path[draw=red,thick,->,line width=2pt] (5) -- (2); \end{tikzpicture} \end{center} -We notice that the color or both node 2 and node 5 +We notice that the color or both nodes 2 and 5 is red, while they are adjacent nodes in the graph. Thus, the graph is not bipartite. diff --git a/luku13.tex b/luku13.tex index e47a31a..8292f2b 100644 --- a/luku13.tex +++ b/luku13.tex @@ -7,7 +7,7 @@ of a graph is an important problem that has many applications in practice. For example, a natural problem in a road network -is to calculate the length of the shorthest route +is to calculate the length of the shortest route between two cities, given the lengths of the roads. In an unweighted graph, the length of a path equals @@ -15,8 +15,8 @@ the number of edges in the path and we can simply use breadth-first search to find the shortest path. However, in this chapter we concentrate on -weighted graphs, -and more sophisticated algorithms +weighted graphs +where more sophisticated algorithms are needed for finding shortest paths. @@ -70,9 +70,8 @@ Each node in the graph is assigned a distance. Initially, the distance to the starting node is 0, and the distance to all other nodes is infinite. -The algorithm searches for edges that reduce the -distances. -First, all edges from node 1 reduce the distances: +The algorithm searches for edges that reduce distances. +First, all edges from node 1 reduce distances: \begin{center} \begin{tikzpicture} \node[draw, circle] (1) at (1,3) {1}; @@ -100,7 +99,7 @@ First, all edges from node 1 reduce the distances: \end{center} After this, edges $2 \rightarrow 5$ and $3 \rightarrow 4$ -reduce the distances: +reduce distances: \begin{center} \begin{tikzpicture} \node[draw, circle] (1) at (1,3) {1}; @@ -156,7 +155,7 @@ and we have successfully calculated the shortest distance from the starting node to all other nodes. -For example, the smallest distance 3 +For example, the shortest distance 3 from node 1 to node 5 corresponds to the following path: @@ -201,9 +200,9 @@ there is an edge to node $x$ with weight $w$. The algorithm consists of $n-1$ rounds, and on each round the algorithm goes through -all edges in the graph and tries to +all edges of the graph and tries to reduce the distances. -The algorithm builds an array \texttt{e} +The algorithm constructs an array \texttt{e} that will contain the distance from $x$ to all nodes in the graph. The initial value $10^9$ means infinity. @@ -228,7 +227,7 @@ all distances are final after $n-1$ rounds, because each shortest path can contain at most $n-1$ edges. In practice, the final distances can usually -be found much faster than in $n-1$ rounds. +be found faster than in $n-1$ rounds. Thus, a possible way to make the algorithm more efficient is to stop the algorithm if no distance can be reduced during a round. @@ -272,7 +271,8 @@ using the Bellman–Ford algorithm by running the algorithm for $n$ rounds. If the last round reduces any distance, the graph contains a negative cycle. -Note that this algorithm searches for +Note that this algorithm can be used to +search for a negative cycle in the whole graph regardless of the starting node. @@ -283,7 +283,7 @@ regardless of the starting node. The \key{SPFA algorithm} (''Shortest Path Faster Algorithm'') is a variant of the Bellman–Ford algorithm, that is often more efficient than the original algorithm. -It does not go through all the edges on each round, +The SPFA algorithm does not go through all the edges on each round, but instead, it chooses the edges to be examined in a more intelligent way. @@ -294,11 +294,11 @@ to the queue. Then, the algorithm always processes the first node in the queue, and when an edge $a \rightarrow b$ reduces a distance, -node $b$ is added to the end of the queue. +node $b$ is added to the queue. -The following implementation uses a -\texttt{queue} structure \texttt{q}. -In addition, the array \texttt{z} indicates +The following implementation uses a +\texttt{queue} \texttt{q}. +In addition, an array \texttt{z} indicates if a node is already in the queue, in which case the algorithm does not add the node to the queue again. @@ -321,11 +321,11 @@ while (!q.empty()) { The efficiency of the SPFA algorithm depends on the structure of the graph: -the algorithm is often very efficient, +the algorithm is often efficient, but its worst case time complexity is still $O(nm)$ and it is possible to create inputs that make the algorithm as slow as the -standard Bellman–Ford algorithm. +original Bellman–Ford algorithm. \section{Dijkstra's algorithm} @@ -342,7 +342,7 @@ are no negative weight edges in the graph. Like the Bellman–Ford algorithm, Dijkstra's algorithm maintains distances -for the nodes and reduces them during the algorithm. +to the nodes and reduces them during the search. Dijkstra's algorithm is efficient, because it only processes each edge in the graph once, using the fact @@ -376,7 +376,7 @@ starting node is node 1: \end{tikzpicture} \end{center} Like in the Bellman–Ford algorithm, -intially the distance to the starting node is 0 +initially the distance to the starting node is 0 and the distance to all other nodes is infinite. At each step, Dijkstra's algorithm selects a node @@ -529,7 +529,7 @@ However, Dijkstra's algorithm finds the path $1 \rightarrow 2 \rightarrow 4$ by following the minimum weight edges. The algorithm does not take into account that -on the lower path, the weight $-5$ +on the other path, the weight $-5$ compensates the previous large weight $6$. \subsubsection{Implementation} @@ -550,7 +550,7 @@ can be retrieved in logarithmic time. In the following implementation, the priority queue contains pairs whose first -element is the current distance of the node and second +element is the current distance to the node and second element is the identifier of the node. \begin{lstlisting} priority_queue> q; @@ -559,12 +559,12 @@ A small difficulty is that in Dijkstra's algorithm, we should find the node with the \emph{minimum} distance, while the C++ priority queue finds the \emph{maximum} element as default. -An easy solution is to use \emph{negative} distances, +An easy trick is to use \emph{negative} distances, which allows us to directly use the C++ priority queue. The code keeps track of processed nodes -in the array \texttt{z}, -and maintains estimated distances in array \texttt{e}. +in an array \texttt{z}, +and maintains the distances in an array \texttt{e}. Initially, the distance to the starting node is 0, and the distance to all other nodes is $10^9$ (infinite). @@ -587,8 +587,8 @@ while (!q.empty()) { The time complexity of the above implementation is $O(n+m \log m)$ because the algorithm goes through -all nodes in the graph, and adds for each edge -at most one estimated distance to the priority queue. +all nodes in the graph and adds for each edge +at most one distance to the priority queue. \section{Floyd–Warshall algorithm} @@ -605,7 +605,7 @@ The algorithm maintains a two-dimensional array that contains distances between the nodes. First, the distances are calculated only using direct edges between the nodes. -After this the algorithm updates the distances +After this the algorithm reduces the distances by using intermediate nodes in the paths. \subsubsection{Example} @@ -654,7 +654,7 @@ that can act as an intermediate node in paths from now on, and the algorithm reduces the distances in the array using this node. -On the first round, node 1 is the intermediate node. +On the first round, node 1 is the new intermediate node. There is a new path between nodes 2 and 4 with length 14, because node 1 connects them. There is also a new path @@ -673,7 +673,7 @@ between nodes 2 and 5 with length 6. \end{center} \vspace{10pt} -On the second round, node 2 is the intermediate node. +On the second round, node 2 is the new intermediate node. This creates new paths between nodes 1 and 3 and between nodes 3 and 5: @@ -690,7 +690,7 @@ and between nodes 3 and 5: \end{center} \vspace{10pt} -On the third round, node 3 is the intermediate round. +On the third round, node 3 is the new intermediate round. There is a new path between nodes 2 and 4: \begin{center} @@ -707,7 +707,7 @@ There is a new path between nodes 2 and 4: \vspace{10pt} The algorithm continues like this, -until all nodes have been intermediate nodes. +until all nodes have been appointed intermediate nodes. After the algorithm has finished, the array contains the minimum distances between any two nodes: @@ -723,8 +723,8 @@ the minimum distances between any two nodes: \end{tabular} \end{center} -For example, the array indicates that the -shortest path between nodes 2 and 4 has length 8. +For example, the array tells us that the +shortest distance between nodes 2 and 4 is 8. This corresponds to the following path: \begin{center} @@ -755,7 +755,7 @@ Floyd–Warshall algorithm that it is easy to implement. The following code constructs a distance matrix \texttt{d} where $\texttt{d}[a][b]$ -is the smallest distance between nodes $a$ and $b$. +is the shortest distance between nodes $a$ and $b$. First, the algorithm initializes \texttt{d} using the adjacency matrix \texttt{v} of the graph ($10^9$ means infinity): @@ -770,7 +770,7 @@ for (int i = 1; i <= n; i++) { } \end{lstlisting} -After this, the shortest paths can be found as follows: +After this, the shortest distances can be found as follows: \begin{lstlisting} for (int k = 1; k <= n; k++) { diff --git a/luku14.tex b/luku14.tex index 9279a63..cdccf57 100644 --- a/luku14.tex +++ b/luku14.tex @@ -8,7 +8,7 @@ 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 -two nodes in a tree. +two nodes of a tree. For example, the following tree consists of 7 nodes and 6 edges: \begin{center} @@ -33,7 +33,7 @@ For example, the following tree consists of 7 nodes and 6 edges: The \key{leaves} of a tree are the nodes with degree 1, i.e., with only one neighbor. -For example, the leaves in the above tree +For example, the leaves of the above tree are nodes 3, 5, 6 and 7. \index{root} @@ -73,7 +73,7 @@ is its upper neighbor. Each node has exactly one parent, except for the root that does not have a parent. For example, in the above tree, -the childern of node 4 are nodes 3 and 7, +the children of node 4 are nodes 3 and 7, and the parent is node 1. \index{subtree} @@ -89,9 +89,9 @@ consists of nodes 4, 3 and 7. Depth-first search and breadth-first search can be used for traversing the nodes in a tree. -However, the traversal is easier to implement than -in a general graph because -there are no cycles in the tree, and it is not +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 possible to reach a node from multiple directions. The typical way to traverse a tree is to start @@ -232,9 +232,9 @@ the longest path from node 1 to a leaf has length 2 $1 \rightarrow 4 \rightarrow 7$ or $1 \rightarrow 2 \rightarrow 6$). After this, the algorithm calculates for each node $x$ the length of the longest path where $x$ -is the turning point of the path. +is the highest point of the path. The longest such path can be found by choosing -two children with longest paths two leaves. +two children with longest paths to leaves. For example, in the above graph, nodes 2 and 4 yield the longest path for node 1. @@ -357,7 +357,7 @@ In the example graph, the distances are as follows: \end{center} \end{samepage} For example, the farthest node from node 4 -in the direction of node 1 is node 6, and the distance to this +in the direction of node 1 is node 6, and the distance to that node is 3 using the path $4 \rightarrow 1 \rightarrow 2 \rightarrow 6$. @@ -500,7 +500,7 @@ For example, the following tree is a binary tree: The nodes in a binary tree have three natural orderings that correspond to different ways to -recursively traverse the nodes: +recursively traverse the tree: \begin{itemize} \item \key{pre-order}: first process the root, @@ -519,7 +519,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 tree above is the only possible 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 diff --git a/luku15.tex b/luku15.tex index 9cb9f30..167f442 100644 --- a/luku15.tex +++ b/luku15.tex @@ -4,7 +4,7 @@ A \key{spanning tree} of a graph consists of the nodes of the graph and some of the -edges of the graph so that there is a unique path +edges of the graph so that there is a path between any two nodes. Like trees in general, spanning trees are connected and acyclic. @@ -54,7 +54,7 @@ $3+5+9+3+2=22$. A \key{minimum spanning tree} is a spanning tree whose weight is as small as possible. -The weight of a minimum spanning tree for the above graph +The weight of a minimum spanning tree for the example graph is 20, and such a tree can be constructed as follows: \begin{center} @@ -82,7 +82,7 @@ is 20, and such a tree can be constructed as follows: In a similar way, a \key{maximum spanning tree} is a spanning tree whose weight is as large as possible. The weight of a maximum spanning tree for the -above graph is 32: +example graph is 32: \begin{center} \begin{tikzpicture}[scale=0.9] @@ -302,7 +302,7 @@ will find a minimum spanning tree? Let us see what happens if the minimum weight edge of the graph is not included in the spanning tree. For example, suppose that a spanning tree -for the above graph would not contain the +for the previous graph would not contain the minimum weight edge 5--6. We do not know the exact structure of such a spanning tree, but in any case it has to contain some edges. @@ -377,7 +377,7 @@ for (...) { The loop goes through the edges in the list and always processes an edge $a$--$b$ where $a$ and $b$ are two nodes. -The code uses two functions: +Two functions are needed: the function \texttt{same} determines if the nodes are in the same component, and the function \texttt{union} @@ -386,10 +386,10 @@ joins the components that contain nodes $a$ and $b$. The problem is how to efficiently implement the functions \texttt{same} and \texttt{union}. One possibility is to implement the function -\texttt{same} as graph traversal and check if -we can reach node $b$ from node $a$. +\texttt{same} as a graph traversal and check if +we can get from node $a$ to node $b$. However, the time complexity of such a function -would be $O(n+m)$, +would be $O(n+m)$ and the resulting algorithm would be slow, because the function \texttt{same} will be called for each edge in the graph. @@ -415,7 +415,7 @@ of the set that contains a given element. In a union-find structure, one element in each set is the representative of the set, -and there is a chain from any other element in the +and there is a chain from any other element of the set to the representative. For example, assume that the sets are $\{1,4,7\}$, $\{5\}$ and $\{2,3,6,8\}$: @@ -439,13 +439,13 @@ $\{1,4,7\}$, $\{5\}$ and $\{2,3,6,8\}$: \end{tikzpicture} \end{center} -In this example the representatives +In this case the representatives of the sets are 4, 5 and 2. For each element, we can find its representative by following the chain that begins at the element. For example, the element 2 is the representative for the element 6, because -there is a chain $6 \rightarrow 3 \rightarrow 2$. +we follow the chain $6 \rightarrow 3 \rightarrow 2$. Two elements belong to the same set exactly when their representatives are the same. @@ -478,20 +478,21 @@ can be joined as follows: The resulting set contains the elements $\{1,2,3,4,6,7,8\}$. -From this on, the element 2 will be the representative +From this on, the element 2 is the representative for the entire set and the old representative 4 -will point to the element 2. +points to the element 2. -The efficiency of the structure depends on -the way the sets are joined. +The efficiency of the union-find structure depends on +how the sets are joined. It turns out that we can follow a simple strategy: always connect the representative of the smaller set to the representative of the larger set (or if the sets are of equal size, we can make an arbitrary choice). Using this strategy, the length of any chain -will be $O(\log n)$, so we can always efficiently -find the representative of any element by following the chain. +will be $O(\log n)$, so we can +find the representative of any element +efficiently by following the corresponding chain. \subsubsection{Implementation} @@ -570,9 +571,9 @@ the smaller set to the larger set. for finding a minimum spanning tree. The algorithm first adds an arbitrary node to the tree. -After this, the algorithm always selects an edge -whose weight is as small as possible and -that adds a new node to the tree. +After this, the algorithm always chooses +a minimum-weight edge that +adds a new node to the tree. Finally, all nodes have been added to the tree and a minimum spanning tree has been found. @@ -627,8 +628,9 @@ Initially, there are no edges between the nodes: \end{tikzpicture} \end{center} An arbitrary node can be the starting node, -so let us select node 1. -First, an edge with weight 3 connects nodes 1 and 2: +so let us choose node 1. +First, we add node 2 that is connected by +an edge of weight 3: \begin{center} \begin{tikzpicture}[scale=0.9] \node[draw, circle] (1) at (1.5,2) {$1$};