blog/content/posts/2024-07-20-treap/index.md

2.5 KiB

title date draft description tags categories series favorite disable_feed graphviz
Treap 2024-07-20T14:12:27+01:00 false A simpler BST
algorithms
data structures
python
programming
Cool algorithms
false false true

The Treap is a mix between a Binary Search Tree and a Heap.

Like a Binary Search Tree, it keeps an ordered set of keys in the shape of a tree, allowing for binary search traversal.

Like a Heap, it associates each node with a priority, making sure that a parent's priority is always higher than any of its children.

What does it do?

By randomizing the priority value of each key at insertion time, we ensure a high likelihook that the tree stays roughly balanced, avoiding degenerating to unbalanced O(N) height.

Here's a sample tree created by inserting integers from 0 to 250 into the tree:

{{< graphviz file="treap.gv" />}}

Implementation

I'll be keeping the theme for this [series] by using Python to implement the Treap. This leads to somewhat annoying code to handle the left/right nodes which is easier to do in C, using pointers.

[series]: {{< ref "/series/cool-algorithms/" >}}

Representation

Creating a new Treap is easy: the tree starts off empty, waiting for new nodes to insert.

Each Node must keep track of the key, the mapped value, and the node's priority (which is assigned randomly). Finally it must also allow for storing two children (left and right).

class Node[K, V]:
    key: K
    value: V
    priority: float
    left: Node[K, V] | None
    righg: Node[K, V] | None

    def __init__(self, key: K, value: V):
        # Store key and value, like a normal BST node
        self.key = key
        self.value = value
        # Priority is derived randomly
        self.priority = random()
        self.left = None
        self.right = None

class Treap[K, V]:
    _root: Node[K, V] | None

    def __init__(self):
        # The tree starts out empty
        self._root = None

Searching the tree is the same as in any other Binary Search Tree.

def get(self, key: K) -> T | None:
    node = self._root
    # The usual BST traversal
    while node is not None:
        if node.key == key:
            return node.value
        elif node.key < key:
            node = node.right
        else:
            node = node.left
    return None