fix: minor typos

Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
Matej Focko 2022-05-18 21:53:45 +02:00
parent 0bbcdf0ea3
commit d3a9ebaf2e
Signed by: mfocko
GPG key ID: 7C47D46246790496
5 changed files with 26 additions and 18 deletions

View file

@ -5,6 +5,6 @@ Data structures have become a regular part of the essential toolbox for problem-
Currently, the most commonly used implementations of sets use hash tables, but we will talk about another common alternative, implementation via self-balancing search trees. Compared to a hash table, they provide consistent time complexity, but at the cost of a requirement for ordering on the elements. The most implemented self-balancing binary tree is a \textit{red-black tree}, as described by \textit{Guibas and Sedgewick}~\cite{rbtree}. Among other alternatives, we can find (non-binary) \textit{B-tree}~\cite{btree} and \textit{AVL tree}~\cite{avl}.
This thesis analyses and visualizes the \textit{Weak AVL (WAVL)}\cite{wavl} tree that has more relaxed conditions than the AVL tree, but still provides better balancing than a red-black tree.
This thesis analyses and visualizes the \textit{Weak AVL (WAVL)}\cite{wavl} tree that has more relaxed conditions than the AVL tree, but still provides better balancing than a red-black tree. The thesis aims to provide study material and a web page that allows visual feedback when performing operations on the WAVL tree.
We start by reiterating through commonly used search trees, explaining basic ideas behind their self-balancing and bounding the height in the worst-case scenario. Then we state used terminology and explain the rank-balanced tree. Given a rank-balanced tree, we can delve into the details behind the representation of previously shown self-balancing binary search trees using rank and the WAVL rule gives us a new self-balancing binary search tree. For the WAVL, we provide pseudocode and explain operations used for rebalancing, including diagrams. Later on, we will discuss different heuristics that can be used for rebalancing and implementing the visualization of the operations on the WAVL tree.

View file

@ -75,15 +75,15 @@ Example of the AVL tree that uses ranks instead of signs or balance-factors can
\textbf{Red-Black Rule}: All rank differences are 0 or 1, and no parent of a 0-child is a 0-child.~\cite{wavl}
In the case of red-black trees, rank represents a number of black nodes on a path from the node to a leaf (excluding the node itself). Based on that, we can discuss the \textit{Red-Black Rule} in detail:
\begin{enumerate}
\item \textit{All rank differences are 0 or 1} inductively enforces a monotonically non-decreasing (at most by 1) count of black nodes from the leaves. In detail:
\begin{enumerate}
\begin{itemize}
\item \textit{All rank differences are 0 or 1} inductively enforces a monotonically non-decreasing (increases at most by 1) count of black nodes from the leaves. In detail:
\begin{itemize}
\item In case the \textbf{current node is black}, the rank difference must be 1, since we have one more black node on the path from the parent to the leaves than from the current node.
\item In case the \textbf{current node is red}, the rank difference must be 0, since from the parent, the count of black nodes on the path to leaves has not changed.
\item And finally, all other differences are invalid since adding a node to the beginning of a path to the leaf, we can either add red node (0-child) or black node (1-child), i.e. there is one more black node on the path or not, which implies the change can be only 0 or 1.
\end{enumerate}
\end{itemize}
\item \textit{No parent of a 0-child is a 0-child} ensures that there are no two consecutive red nodes, since the 0-child node is equivalent to the red node.
\end{enumerate}
\end{itemize}
An example of the red-black tree that uses ranks instead of colours can be seen in \autoref{fig:ranked:rbt}. Red nodes are also coloured for convenience.
@ -144,7 +144,7 @@ However, it is also possible to colour edges instead of the nodes as is presente
\section{Implementation of other balanced trees using rank}
To show that using rank is mostly an implementation detail, we will describe an implementation of the AVL tree using rank.
Implementation of the insertion is trivial, since it is described by \textit{Haeupler et al.}~\cite{wavl} and is used in the WAVL tree. All we need to implement is the deletion from the AVL tree. We will start with a short description of the deletion rebalance as given by \textit{Mareš and Valla} in \textit{Průvodce labyrintem algoritmů}.
Implementation of the insertion is trivial, since it is described by \textit{Haeupler et al.}~\cite{wavl} and is used in the WAVL tree. All we need to implement is the deletion from the AVL tree. We will start with a short description of the deletion rebalance as given by \textit{Mareš and Valla} in \textit{Průvodce labyrintem algoritmů}~\cite{labyrint}.
When propagating the error, we can encounter 3 cases (we explain them for propagating deletion from the left subtree, propagation from right is mirrored, and role of trits $+$ and $-$ swaps)~\cite{labyrint}:
\begin{enumerate}
@ -185,7 +185,7 @@ Knowing rules, we have implemented the deletion rebalance by implementing the fo
}
}
}
\caption{\texttt{deleteRebalance} algorithm for the AVL tree}\label{algorithm:avl:deleteRebalance}
\caption{\texttt{deleteRebalance} algorithm for the AVL tree.}\label{algorithm:avl:deleteRebalance}
\end{algorithm}
\texttt{deleteRebalance}, as can be seen in \autoref{algorithm:avl:deleteRebalance}, is relatively straightforward. In the beginning, we early return in case there is nothing to be rebalanced, which happens when deleting the last node from the tree. Then we handle a case where we are given only parent by correctly setting $y$ and $parent$. Following up on that, as long as we have a node to be checked, we call \autoref{algorithm:avl:deleteFixNode} to fix the balancing of the current node. The algorithm for fixing a node returns $true$ or $false$ depending on the need to propagate the height change further, which is utilized in the \texttt{while}-loop condition.
@ -210,7 +210,7 @@ Knowing rules, we have implemented the deletion rebalance by implementing the fo
\Return{$\avlDeleteRotate(T, x, l, -1, rotateR, rotateL)$}\;
}
}
\caption{\texttt{deleteFixNode} algorithm for the AVL tree}\label{algorithm:avl:deleteFixNode}
\caption{\texttt{deleteFixNode} algorithm for the AVL tree.}\label{algorithm:avl:deleteFixNode}
\end{algorithm}
\texttt{deleteFixNode} implements the algorithm described in \hyperref[avl:rules:delete]{the list} with all possible cases above. We start by checking the balance factor of the given node. In case there is no need to rotate, the rank gets updated if necessary, and then we return the information on whether there is a need to propagate further or not. If the node has acquired a balance factor of $2$, we call \autoref{algorithm:avl:deleteRotate} to fix the balancing locally.
@ -238,11 +238,11 @@ There are two operations that are not described using helper functions, and they
\BlankLine
\Return{$f \neq 0$}\;
}
\caption{\texttt{deleteRotate} algorithm for the AVL tree}\label{algorithm:avl:deleteRotate}
\caption{\texttt{deleteRotate} algorithm for the AVL tree.}\label{algorithm:avl:deleteRotate}
\end{algorithm}
\newpage
\texttt{deleteRotate} is handling only fixes where the rotations are required. Both \autoref{algorithm:avl:deleteFixNode} and \autoref{algorithm:avl:deleteRotate} include comments to highlight which rules are handled. This function is also done generically regardless of the subtree from which the height change is being propagated. This is done by passing in functions used for rotations (since it is mirrored) and passing in the balance factor required for just one rotation.
There is a crucial difference between \autoref{algorithm:avl:deleteFixNode} and \autoref{algorithm:avl:deleteRotate} compared to the AVL tree implementations without ranks. If we compare the rules for deletion with algorithms for rank-balanced implementation, we can see a crucial difference. During propagation of the height change, the balance factors of the closest nodes are already adjusted. That is caused by the calculation of the balance factor based on the subtrees, not the node's rank. Furthermore, subtrees are already adjusted. This fact needs to be reflected in the implementation accordingly. It shifts the meaning of the rules described above and is written for the implementations that directly store the trit in the nodes, updated manually during rebalancing.
There is a crucial difference between \autoref{algorithm:avl:deleteFixNode} and \autoref{algorithm:avl:deleteRotate} compared to the AVL tree implementations without ranks. If we compare the rules for deletion with algorithms for rank-balanced implementation, we can see a crucial difference. During propagation of the height change, the balance factors of the closest nodes are already adjusted. That is caused by the calculation of the balance factor based on the subtrees, not the node's rank. Furthermore, subtrees are already adjusted. This fact needs to be reflected in the implementation accordingly. It shifts the meaning of the rules described above and is written for the implementations that directly store the trit in the nodes, and update it manually during rebalancing.

View file

@ -4,7 +4,7 @@ This chapter will briefly discuss the properties and fundamental ideas behind th
\section{Red-black trees}
As mentioned previously, red-black trees are among the most popular implementations in standard libraries. We have a binary search tree, and each node is given \textit{red} or \textit{black} colour. A red-black tree is kept balanced by enforcing the following set of rules~\cite{rbtree}:
Red-black trees are among the most popular implementations in standard libraries. We have a binary search tree, and each node is given \textit{red} or \textit{black} colour. A red-black tree is kept balanced by enforcing the following set of rules~\cite{rbtree}:
\begin{enumerate}
\item External nodes are black; internal nodes may be red or black.
@ -41,7 +41,7 @@ BalanceFactor(n) \in \{ -1, 0, 1 \}
In other words, the heights of left and right subtrees of each node differ at most in 1.~\cite{avl}
Similarly, we will deduce the height of the AVL tree from the original paper, by \textit{Adelson-Velsky and Landis}~\cite{avl}:
Similarly, we will deduce the height of the AVL tree from the original paper by \textit{Adelson-Velsky and Landis}~\cite{avl} and also from \textit{The Art of Computer Programming} by \textit{Knuth}~\cite{knuth1998art}:
\begin{equation}
\left( \log_2{(n + 1)} \leq \right) h < \log_{\varphi}{(n + 1)} < \frac{3}{2} \cdot \log_2{(n + 1)}
\end{equation}~\label{avl-height}

View file

@ -31,13 +31,13 @@ For the visualization of two trees at once, we have decided to prepare the follo
\begin{figure}
\centering
\includegraphics[scale=0.20,angle=90]{visualization.png}
\caption{Visualization of chosen tree}
\caption{Visualization of a chosen tree.}
\label{fig:visualization}
\end{figure}
\begin{figure}
\centering
\includegraphics[scale=0.20,angle=90]{comparator.png}
\caption{Comparator part of the visualization}
\caption{Comparator part of the visualization.}
\label{fig:comparator}
\end{figure}

View file

@ -129,7 +129,7 @@ As a first step, which can be seen in \autoref{algorithm:wavl:insertRebalance},
After this, we might end up in two situations, and those are:
\begin{enumerate}
\item The current node is not a 0-child, which means that after propagation and promotions we have gotten to a parent node that is (1,~2), which refers to \hyperref[avl:rules:insert:1]{\textit{rule 1}}.
\item The current node is a 0-child, which means that after propagation and promotions, we have a node with a parent that is either (0,~2)-node. This case conforms to \hyperref[avl:rules:insert:3]{\textit{rule 3}} and must be handled further to fix the broken rank rule.
\item The current node is a 0-child, which means that after propagation and promotions, we have a node with a parent that is (0,~2)-node. This case conforms to \hyperref[avl:rules:insert:3]{\textit{rule 3}} and must be handled further to fix the broken rank rule.
\end{enumerate}
\hyperref[avl:rules:insert:3]{\textit{Rule 3}} is then handled by a helper function that can be seen in \autoref{algorithm:wavl:fix0Child}.
@ -208,7 +208,7 @@ As described by \textit{Haeupler et al.}~\cite{wavl}, we start the deletion reba
\pgfsetstrokecolor{strokecol}
%
\end{tikzpicture}
\caption{\autoref{fig:wavl:twoElements} after deletion of 2}
\caption{\autoref{fig:wavl:twoElements} after deletion of 2.}
\label{fig:wavl:twoElementsAfterDelete}
\end{figure}
@ -347,4 +347,12 @@ The propagation happens by demoting the parent and possibly sibling of $x$. In t
\caption{Final phase of the deletion rebalance after deletion from the WAVL tree.}\label{algorithm:wavl:fixDelete}
\end{algorithm}
The final part happens when it is not possible to propagate the error further. In that case, we perform either single or double rotation.
The final part happens when it is not possible to propagate the error further. In that case, we perform either single or double rotation.
\section{Heuristics}
\textit{Haeupler et al.}~\cite{wavl} also present different heuristics for the rebalancing of the WAVL tree. In this thesis, we present algorithms for bottom-up rebalancing. Regarding top-down rebalancing, it can be compared to the preemptive algorithms on the B-tree that we mentioned in \autoref{chap:sb-bst}. It can be described in the following way:
When inserting the key to the WAVL tree, we promote every (1,~1)-node that we encounter on the way down to the parent node.
When deleting the key from the WAVL tree, we analogically demote every (2,~2)-node that we encounter on the way down to the parent node.