Leftist tree

Last updated

In computer science, a leftist tree or leftist heap is a priority queue implemented with a variant of a binary heap. Every node x has an s-value which is the distance to the nearest leaf in subtree rooted at x. [1] In contrast to a binary heap, a leftist tree attempts to be very unbalanced. In addition to the heap property, leftist trees are maintained so the right descendant of each node has the lower s-value.

Contents

The height-biased leftist tree was invented by Clark Allan Crane. [2] The name comes from the fact that the left subtree is usually taller than the right subtree.

A leftist tree is a mergeable heap. When inserting a new node into a tree, a new one-node tree is created and merged into the existing tree. To delete an item, it is replaced by the merge of its left and right sub-trees. Both these operations take O(log n) time. For insertions, this is slower than Fibonacci heaps, which support insertion in O(1) (constant) amortized time, and O(log n) worst-case.

Leftist trees are advantageous because of their ability to merge quickly, compared to binary heaps which take Θ(n). In almost all cases, the merging of skew heaps has better performance. However merging leftist heaps has worst-case O(log n) complexity while merging skew heaps has only amortized O(log n) complexity.

Bias

The usual leftist tree is a height-biased leftist tree. [2] However, other biases can exist, such as in the weight-biased leftist tree. [3]

S-value

S-values of a leftist tree Leftist-trees-S-value.svg
S-values of a leftist tree

The s-value (or rank) of a node is the distance from that node to the nearest empty position in the subtree rooted at that node. Put another way, the s-value of a null child is implicitly zero. Other nodes have an s-value equal to one more the minimum of their children's s-values. Thus, in the example at right, all nodes with at least one missing child have an s-value of 1, while node 4 has an s-value of 2, since its right child (8) has an s-value of 1. (In some descriptions, the s-value of null children is assumed to be −1. [4] )

Knowing the shortest path to the nearest missing leaf in the subtree rooted at x is exactly of s(x), every node at depth s(x)−1 or less has exactly 2 children since s(x) would have been less if not. Meaning that the size of the tree rooted at x is at least . Thus, s(x) is at most , m being the number of nodes of the subtree rooted at x. [1]

Operations on a height biased leftist tree

Most operations on a Height Biased Leftist Tree are done using the merge operation. [1]

Merging two Min HBLTs

The merge operation takes two Min HBLTs as input and returns a Min HBLT containing all the nodes in the original Min HBLTs put together.

If either of A or B is empty, the merge returns the other one.

In case of Min HBLTs, assume we have two trees rooted at A and B where A.key B.key. Otherwise we can swap A and B so that the condition above holds.

The merge is done recursively by merging B with A's right subtree. This might change the S-value of A's right subtree. To maintain the leftist tree property, after each merge is done, we check if the S-value of right subtree became bigger than the S-value of left subtree during the recursive merge calls. If so, we swap the right and left subtrees (If one child is missing, it should be the right one).

Since we assumed that A's root is greater than B's, the heap property is also maintained.

Pseudocode for merging two min height biased leftist trees

MERGE(A, B)     if A = null return B     if B = null return A     if A.key > B.key return MERGE(B, A)     A.right := MERGE (A.right, B) // the result cannot be null since B is non-nullif A.left = null then         SWAP(A.left, A.right)         A.s_value := 1 // since the right subtree is null, the shortest path to a descendant leaf from node A is 1return A     if A.right.s_value > A.left.s_value then         SWAP (A.right, A.left)     A.s_value := A.right.s_value + 1     return A

Java code for merging two min height biased leftist trees

publicNodemerge(Nodex,Nodey){if(x==null)returny;if(y==null)returnx;// if this were a max-heap, then the // next line would be: if (x.element < y.element)if(x.element.compareTo(y.element)>0)// x.element > y.elementreturnmerge(y,x);x.rightChild=merge(x.rightChild,y);if(x.leftChild==null){// left child doesn't exist, so move right child to the left sidex.leftChild=x.rightChild;x.rightChild=null;// x.s was, and remains, 1}else{// left child does exist, so compare s-valuesif(x.leftChild.s<x.rightChild.s){Nodetemp=x.leftChild;x.leftChild=x.rightChild;x.rightChild=temp;}// since we know the right child has the lower s-value, we can just// add one to its s-valuex.s=x.rightChild.s+1;}returnx;}

Haskell code for merging two min height biased leftist trees

dataLHeapa=Leaf|Nodea(LHeapa)(LHeapa)rank::LHeapa->IntegerrankLeaf=0rank(Node__r)=rankr+1merge::Orda=>LHeapa->LHeapa->LHeapamergeLeafh=hmergehLeaf=hmergeh@(Nodealr)h'@(Nodea'__)|a>a'=mergeh'h|rankr'>rankl=Nodear'l|otherwise=Nodealr'wherer'=mergerh'

Example

An example of how the merge operation in a leftist tree works is depicted. The boxes represent each merge call.

When the recursion unwinds, we swap left and right children if x.right.s_value > x.left.s_value for every node x. In this case we swapped the subtrees rooted at nodes with keys 7 and 10.

Insertion into a Min HBLT

Insertion is done using the merge operation. An insertion of a node into an already existing

Min HBLT, creates a HBLT tree of size one with that node and merges it with the existing tree.

INSERT (A, x)     B := CREATE_TREE(x)     return MERGE(A, B)

Deletion of Min element from Min HBLT

The Min element in a Min HBLT is the root. Thus, in order to delete the Min, the root is deleted and its subtrees are merged to form the new Min HBLT.

DELETE_MIN(A)     x := A.key     A := MERGE (A.right, A.left)     returnx

Initializing a height biased leftist tree

Initializing a min HBLT - Part 1 Min-height-biased-leftist-tree-initialization-part1.png
Initializing a min HBLT - Part 1

Initializing a height biased leftist tree is primarily done in one of two ways. The first is to merge each node one at a time into one HBLT. This process is inefficient and takes O(nlogn) time. The other approach is to use a queue to store each node and resulting tree. The first two items in the queue are removed, merged, and placed back into the queue. This can initialize a HBLT in O(n) time. This approach is detailed in the three diagrams supplied. A min height biased leftist tree is shown.

To initialize a min HBLT, place each element to be added to the tree into a queue. In the example (see Part 1 to the left), the set of numbers [4, 8, 10, 9, 1, 3, 5, 6, 11] are initialized. Each line of the diagram represents another cycle of the algorithm, depicting the contents of the queue. The first five steps are easy to follow. Notice that the freshly created HBLT is added to the end of the queue. In the fifth step, the first occurrence of an s-value greater than 1 occurs. The sixth step shows two trees merged with each other, with predictable results.

Initializing a min HBLT - Part 2 Min-height-biased-leftist-tree-initialization-part2.png
Initializing a min HBLT - Part 2

In part 2 a slightly more complex merge happens. The tree with the lower value (tree x) has a right child, so merge must be called again on the subtree rooted by tree x's right child and the other tree. After the merge with the subtree, the resulting tree is put back into tree x. The s-value of the right child (s=2) is now greater than the s-value of the left child (s=1), so they must be swapped. The s-value of the root node 4 is also now 2.

Initializing a min HBLT - Part 3 Min-height-biased-leftist-tree-initialization-part3.png
Initializing a min HBLT - Part 3

Part 3 is the most complex. Here, we recursively call merge twice (each time with the right child 's subtree that is not grayed out). This uses the same process described for part 2.

Deletion of an arbitrary element from a Min HBLT

HBLT 9.png

If we have a pointer to a node x in a Min HBLT, we can delete it as follows: Replace the node x with the result of merging its two subtrees and update the s-values of the nodes on the path from x to the root, swapping the right and left subtrees if necessary to maintain the leftist tree property.

The upward traversal is continued until either we hit the root or the s-values does not change. Since we are deleting an element, the S-values on the path traversed cannot be increased. Every node that is already the right child of its parent and causes its parent's s-value to be decreased, will remain on the right. Every node that is its parent's left child and causes the parent's s-value to be decreased has to be swapped with its right sibling if the s-value becomes lower than the current s-value of the right child.

Each node needs to have a pointer to its parent, so that we can traverse the path to the root updating the s-values.

When the traversal ends at some node y, the nodes traversed all lie on the rightmost path rooted at node y. An example is shown below. It follows that the number of nodes traversed is at most log(m), m being the size of the subtree rooted at y. Thus, this operation also takes O(lg m) to perform.

Weight biased leftist tree [5]

Leftist trees can also be weight biased. In this case, instead of storing s-values in node x, we store an attribute w(x) denoting the number of nodes in the subtree rooted at x:

w(x) = w(x.right) + w(x.left) + 1

WBLTs ensure w(x.left) ≥ w(x.right) for all internal nodes x. WBLT operations ensure this invariant by swapping the children of a node when the right subtree outgrows the left one, just as in HBLT operations.

Merging two Min WBLTs

The merge operation in WBLTs can be done using a single top to bottom traversal since the number of nodes in the subtrees are known prior to recursive call to merge. Thus, we can swap left and right subtrees if the total number of nodes in the right subtree and the tree to be merged is bigger than the number of nodes in the left subtree. This allows the operations be completed in a single path and so improves the time complexity of the operations by a constant factor.

The merge operation is depicted in the graph below.

Other operations on WBLT

HBLT vs WBLT.png

Insertions and deletion of the min element can be done in the same as for HBLTs using the merge operation.

Although WBLTs outperform HBLTs in merge, insertion and deletion of the Min key by a constant factor, the O(log n) bound is not guaranteed when deleting an arbitrary element from WBLTs, since θ(n) nodes have to be traversed.

If this was an HBLT, then deleting the leaf node with key 60 would take O(1) time and updating the s-values is not needed since the length of rightmost path for all the nodes does not change.

But in an WBLT tree, we have to update the weight of each node back to the root, which takes O(n) worst case.

Variants

Several variations on the basic leftist tree exist, which make only minor changes to the basic algorithm:

Related Research Articles

<span class="mw-page-title-main">AVL tree</span> Self-balancing binary search tree

In computer science, an AVL tree is a self-balancing binary search tree (BST). It was the first such data structure to be invented. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Lookup, insertion, and deletion all take O(log n) time in both the average and worst cases, where is the number of nodes in the tree prior to the operation. Insertions and deletions may require the tree to be rebalanced by one or more tree rotations.

<span class="mw-page-title-main">Binary search tree</span> Rooted binary tree data structure

In computer science, a binary search tree (BST), also called an ordered or sorted binary tree, is a rooted binary tree data structure with the key of each internal node being greater than all the keys in the respective node's left subtree and less than the ones in its right subtree. The time complexity of operations on the binary search tree is directly proportional to the height of the tree.

In computer science, a B-tree is a self-balancing tree data structure that maintains sorted data and allows searches, sequential access, insertions, and deletions in logarithmic time. The B-tree generalizes the binary search tree, allowing for nodes with more than two children. Unlike other self-balancing binary search trees, the B-tree is well suited for storage systems that read and write relatively large blocks of data, such as databases and file systems.

<span class="mw-page-title-main">Heap (data structure)</span> Computer science data structure

In computer science, a heap is a specialized tree-based data structure which is essentially an almost complete tree that satisfies the heap property: in a max heap, for any given node C, if P is a parent node of C, then the key of P is greater than or equal to the key of C. In a min heap, the key of P is less than or equal to the key of C. The node at the "top" of the heap is called the root node.

A splay tree is a binary search tree with the additional property that recently accessed elements are quick to access again. Like self-balancing binary search trees, a splay tree performs basic operations such as insertion, look-up and removal in O(log n) amortized time. For random access patterns drawn from a non-uniform random distribution, their amortized time can be faster than logarithmic, proportional to the entropy of the access pattern. For many patterns of non-random operations, also, splay trees can take better than logarithmic time, without requiring advance knowledge of the pattern. According to the unproven dynamic optimality conjecture, their performance on all access patterns is within a constant factor of the best possible performance that could be achieved by any other self-adjusting binary search tree, even one selected to fit that pattern. The splay tree was invented by Daniel Sleator and Robert Tarjan in 1985.

<span class="mw-page-title-main">Binary heap</span> Variant of heap data structure

A binary heap is a heap data structure that takes the form of a binary tree. Binary heaps are a common way of implementing priority queues. The binary heap was introduced by J. W. J. Williams in 1964, as a data structure for heapsort.

<span class="mw-page-title-main">Smoothsort</span> Comparison-based sorting algorithm

In computer science, smoothsort is a comparison-based sorting algorithm. A variant of heapsort, it was invented and published by Edsger Dijkstra in 1981. Like heapsort, smoothsort is an in-place algorithm with an upper bound of O(n log n), but it is not a stable sort. The advantage of smoothsort is that it comes closer to O(n) time if the input is already sorted to some degree, whereas heapsort averages O(n log n) regardless of the initial sorted state.

<span class="mw-page-title-main">Treap</span>

In computer science, the treap and the randomized binary search tree are two closely related forms of binary search tree data structures that maintain a dynamic set of ordered keys and allow binary searches among the keys. After any sequence of insertions and deletions of keys, the shape of the tree is a random variable with the same probability distribution as a random binary tree; in particular, with high probability its height is proportional to the logarithm of the number of keys, so that each search, insertion, or deletion operation takes logarithmic time to perform.

In computer science, a binomial heap is a data structure that acts as a priority queue but also allows pairs of heaps to be merged. It is important as an implementation of the mergeable heap abstract data type, which is a priority queue supporting merge operation. It is implemented as a heap similar to a binary heap but using a special tree structure that is different from the complete binary trees used by binary heaps. Binomial heaps were invented in 1978 by Jean Vuillemin.

In computer science, tree traversal is a form of graph traversal and refers to the process of visiting each node in a tree data structure, exactly once. Such traversals are classified by the order in which the nodes are visited. The following algorithms are described for a binary tree, but they may be generalized to other trees as well.

An AA tree in computer science is a form of balanced tree used for storing and retrieving ordered data efficiently. AA trees are named after Arne Andersson, the one who theorized them.

A pairing heap is a type of heap data structure with relatively simple implementation and excellent practical amortized performance, introduced by Michael Fredman, Robert Sedgewick, Daniel Sleator, and Robert Tarjan in 1986. Pairing heaps are heap-ordered multiway tree structures, and can be considered simplified Fibonacci heaps. They are considered a "robust choice" for implementing such algorithms as Prim's MST algorithm, and support the following operations :

A skew heap is a heap data structure implemented as a binary tree. Skew heaps are advantageous because of their ability to merge more quickly than binary heaps. In contrast with binary heaps, there are no structural constraints, so there is no guarantee that the height of the tree is logarithmic. Only two conditions must be satisfied:

A link/cut tree is a data structure for representing a forest, a set of rooted trees, and offers the following operations:

<span class="mw-page-title-main">Cartesian tree</span>

In computer science, a Cartesian tree is a binary tree derived from a sequence of numbers; it can be uniquely defined from the properties that it is heap-ordered and that a symmetric (in-order) traversal of the tree returns the original sequence. Introduced by Vuillemin (1980) in the context of geometric range searching data structures, Cartesian trees have also been used in the definition of the treap and randomized binary search tree data structures for binary search problems. The Cartesian tree for a sequence may be constructed in linear time using a stack-based algorithm for finding all nearest smaller values in a sequence.

In computer science, a double-ended priority queue (DEPQ) or double-ended heap is a data structure similar to a priority queue or heap, but allows for efficient removal of both the maximum and minimum, according to some ordering on the keys (items) stored in the structure. Every element in a DEPQ has a priority or value. In a DEPQ, it is possible to remove the elements in both ascending as well as descending order.

In computer science, a min-max heap is a complete binary tree data structure which combines the usefulness of both a min-heap and a max-heap, that is, it provides constant time retrieval and logarithmic time removal of both the minimum and maximum elements in it. This makes the min-max heap a very useful data structure to implement a double-ended priority queue. Like binary min-heaps and max-heaps, min-max heaps support logarithmic insertion and deletion and can be built in linear time. Min-max heaps are often represented implicitly in an array; hence it's referred to as an implicit data structure.

<span class="mw-page-title-main">Queap</span>

In computer science, a queap is a priority queue data structure. The data structure allows insertions and deletions of arbitrary elements, as well as retrieval of the highest-priority element. Each deletion takes amortized time logarithmic in the number of items that have been in the structure for a longer time than the removed item. Insertions take constant amortized time.

In computer science, a randomized meldable heap is a priority queue based data structure in which the underlying structure is also a heap-ordered binary tree. However, there are no restrictions on the shape of the underlying binary tree.

In computer science, a weak heap is a data structure for priority queues, combining features of the binary heap and binomial heap. It can be stored in an array as an implicit binary tree like a binary heap, and has the efficiency guarantees of binomial heaps.

References

  1. 1 2 3 "Leftist Trees" (PDF). www.google.com. Retrieved 2019-05-31.
  2. 1 2 Crane, Clark A. (1972), Linear Lists and Priority Queues as Balanced Binary Trees (Ph.D. thesis), Department of Computer Science, Stanford University, ISBN   0-8240-4407-X, STAN-CS-72-259
  3. Seonghun Cho; Sartaj Sahni (1996), "Weight Biased Leftist Trees and Modified Skip Lists" (PDF), Journal of Experimental Algorithmics, 3, CiteSeerX   10.1.1.13.2962 , doi:10.1145/297096.297111
  4. Stewart, James (25 September 1988). "LEFTIST TREES". University of Toronto Dynamic Graphics Project. Retrieved 2019-05-31.
  5. Cho, Seonghun; Sahni, Sartaj (September 1998). "Weight-biased Leftist Trees and Modified Skip Lists". J. Exp. Algorithmics. 3. doi:10.1145/297096.297111. ISSN   1084-6654.

Further reading