diff --git a/luku09.tex b/luku09.tex index 5331558..9a458e8 100644 --- a/luku09.tex +++ b/luku09.tex @@ -702,7 +702,7 @@ Suppose that the binary indexed tree is stored in an array \texttt{b}. The following function calculates the sum of elements in a range $[1,k]$: \begin{lstlisting} -int sum(int k) { +int rsq(int k) { int s = 0; while (k >= 1) { s += b[k]; @@ -755,12 +755,19 @@ memory and is a bit more difficult to implement. A segment tree is a binary tree that contains $2n-1$ nodes. The nodes on the bottom level of the tree -correspond to the original array, +correspond to the array elements, and the other nodes contain information needed for processing range queries. -We will first discuss segment trees that support -sum queries. As an example, consider the following array: +Throughout the section, we assume that the size +of the array is a power of two and zero-based +indexing is used, because it is convenient to build +a segment tree for such an array. +If the size of the array is not a power of two, +we can always append extra elements to it. + +We will first discuss segment trees that support sum queries. +As an example, consider the following array: \begin{center} \begin{tikzpicture}[scale=0.7] \draw (0,0) grid (8,1); @@ -774,15 +781,15 @@ sum queries. As an example, consider the following array: \node at (6.5,0.5) {$2$}; \node at (7.5,0.5) {$6$}; -% \footnotesize -% \node at (0.5,1.4) {$1$}; -% \node at (1.5,1.4) {$2$}; -% \node at (2.5,1.4) {$3$}; -% \node at (3.5,1.4) {$4$}; -% \node at (4.5,1.4) {$5$}; -% \node at (5.5,1.4) {$6$}; -% \node at (6.5,1.4) {$7$}; -% \node at (7.5,1.4) {$8$}; +\footnotesize +\node at (0.5,1.4) {$0$}; +\node at (1.5,1.4) {$1$}; +\node at (2.5,1.4) {$2$}; +\node at (3.5,1.4) {$3$}; +\node at (4.5,1.4) {$4$}; +\node at (5.5,1.4) {$5$}; +\node at (6.5,1.4) {$6$}; +\node at (7.5,1.4) {$7$}; \end{tikzpicture} \end{center} The corresponding segment tree is as follows: @@ -833,15 +840,6 @@ node is the sum of the corresponding array elements, and it can be calculated as the sum of the values of its left and right child node. -It is convenient to build a segment tree -for an array whose size is a power of two, -because in this case every internal node has a left -and right child. -In the sequel, we will assume that the tree -is built like this. -If the size of the array is not a power of two, -we can always add zero elements to the array. - \subsubsection{Range query} The sum of elements in a given range @@ -875,7 +873,7 @@ For example, consider the following range: The sum of elements in the range is $6+3+2+7+2+6=26$. The following two nodes in the tree -cover the range: +correspond to the range: \begin{center} \begin{tikzpicture}[scale=0.7] \draw (0,0) grid (8,1); @@ -921,7 +919,7 @@ that are located as high as possible in the tree, at most two nodes on each level of the tree are needed. Hence, the total number of nodes -examined is only $O(\log n)$. +is only $O(\log n)$. \subsubsection{Array update} @@ -985,10 +983,11 @@ so each update changes $O(\log n)$ nodes in the tree. A segment tree can be stored in an array of $2N$ elements where $N$ is a power of two. -From now on, we will assume that the indices -of the original array are between $0$ and $N-1$. +Such a tree corresponds to an array +indexed from $0$ to $N-1$. -The element at position 1 in the array +In the segment tree array, +the element at position 1 corresponds to the top node of the tree, the elements at positions 2 and 3 correspond to the second level of the tree, and so on. @@ -1082,18 +1081,18 @@ for a node at position $k$, \item the left child node is at position $2k$, and \item the right child node is at position $2k+1$. \end{itemize} -Note that this implies that the index of a node -is even if it is a left child and odd if it is a right child. +% Note that this implies that the index of a node +% is even if it is a left child and odd if it is a right child. \subsubsection{Functions} -We assume that the segment tree is stored +Assume that the segment tree is stored in an array \texttt{p}. The following function calculates the sum of elements in a range $[a,b]$: \begin{lstlisting} -int sum(int a, int b) { +int rsq(int a, int b) { a += N; b += N; int s = 0; while (a <= b) { @@ -1105,15 +1104,15 @@ int sum(int a, int b) { } \end{lstlisting} -The function maintains a range in the segment tree array. -Initially the range is $[a+N,b+N]$, -that corresponds to the range $[a,b]$ -in the underlying array. +The function starts at the bottom of the tree +and moves one level up at each step. +Initially, the range $[a+N,b+N]$ corresponds +to the range $[a,b]$ in the original array. At each step, the function adds the value of the left and right node to the sum if their parent nodes do not belong to the range. -After this, the same process continues on the -next level of the tree. +This process continues, until the sum of the +range has been calculated. The following function increases the value of the element at position $k$ by $x$: @@ -1140,11 +1139,13 @@ and the operations move one level forward in the tree at each step. \subsubsection{Other queries} -A segment tree can support any query -where the answer for a range $[a,b]$ -can be calculated -from the answers for ranges $[a,c]$ and $[c+1,b]$, where -$c$ is some index between $a$ and $b$. +A segment tree can support any queries +as long as the results of the queries +can be combined efficiently; +if the results for ranges $[a,b]$ and $[c,d]$ +are known and $b$ and $c$ are two adjacent positions, +it should be easy to compute the result +for the range $[x,z]$. Examples of such queries are minimum and maximum, greatest common divisor, and bit operations and, or and xor. @@ -1195,7 +1196,7 @@ supports minimum queries: In this segment tree, every node in the tree contains the smallest element in the corresponding -range of the underlying array. +range of the array. The top node of the tree contains the smallest element in the whole array. The operations can be implemented like previously, @@ -1205,7 +1206,7 @@ but instead of sums, minima are calculated. The structure of the segment tree allows us to use binary search for finding elements in the array. -For example, if the tree supports the minimum query, +For example, if the tree supports minimum queries, we can find the position of the smallest element in $O(\log n)$ time. @@ -1266,7 +1267,7 @@ by traversing a path downwards from the top node: A limitation in data structures that are built upon an array is that the elements are indexed using integers -$1,2,3,$ etc. +consecutive integers. Difficulties arise when large indices are needed. For example, if we wish to use the index $10^9$, @@ -1278,7 +1279,7 @@ elements which is not realistic. However, we can often bypass this limitation by using \key{index compression}, where the original indices are replaced -with the indices $1,2,3,$ etc. +with indices $1,2,3,$ etc. This can be done if we know all the indices needed during the algorithm beforehand. @@ -1288,7 +1289,7 @@ compresses the indices. We require that the order of the indices does not change, so if $a