Compare commits

...

5 commits

Author SHA1 Message Date
Bruno BELANYI 691cf704f4 Add Treap Revisited post
Some checks failed
ci/woodpecker/push/deploy/2 Pipeline failed
ci/woodpecker/cron/deploy/2 Pipeline failed
2024-07-27 18:41:07 +01:00
Bruno BELANYI aa72b269c2 posts: treap: add removal 2024-07-27 18:41:07 +01:00
Bruno BELANYI eaaa9c9ae2 posts: treap-revisited: add insertion 2024-07-27 18:41:07 +01:00
Bruno BELANYI b3ed39eef3 posts: treap: add merge 2024-07-27 18:41:07 +01:00
Bruno BELANYI aee1fa55c8 posts: treap-revisited: add split 2024-07-27 18:41:07 +01:00

View file

@ -36,3 +36,111 @@ operations: `split` and `merge`.
We'll be reusing the same structures as in the last post, so let's skip straight We'll be reusing the same structures as in the last post, so let's skip straight
to implementing those fundaments, and building on them for `insert` and to implementing those fundaments, and building on them for `insert` and
`delete`. `delete`.
### Split
Splitting a tree means taking a key, and getting the following output:
* a `left` node, root of the tree of all keys lower than the input.
* an extracted `node` which corresponds to the input `key`.
* a `right` node, root of the tree of all keys higher than the input.
```python
type OptionalNode[K, V] = Node[K, V] | None
class SplitResult(NamedTuple):
left: OptionalNode
node: OptionalNode
right: OptionalNode
def split(root: OptionalNode[K, V], key: K) -> SplitResult:
# Base case, empty tree
if root is None:
return SplitResult(None, None, None)
# If we found the key, simply extract left and right
if root.key == key:
left, right = root.left, root.right
root.left, root.right = None, None
return SplitResult(left, root, right)
# Otherwise, recurse on the corresponding side of the tree
if root.key < key:
left, node, right = split(root.right, key)
root.right = left
return SplitResult(root, node, right)
if key < root.key:
left, node, right = split(root.left, key)
root.left = right
return SplitResult(left, node, root)
raise RuntimeError("Unreachable")
```
### Merge
Merging a `left` and `right` tree means (cheaply) building a new tree containing
both of them. A pre-condition for merging is that the `left` tree is composed
entirely of nodes that are lower than any key in `right` (i.e: as in `left` and
`right` after a `split`).
```python
def merge(
left: OptionalNode[K, V],
right: OptionalNode[K, V],
) -> OptionalNode[K, V]:
# Base cases, left or right being empty
if left is None:
return right
if right is None:
return left
# Left has higher priority, it must become the root node
if left.priority >= right.priority:
# We recursively reconstruct its right sub-tree
left.right = merge(left.right, right)
return left
# Right has higher priority, it must become the root node
if left.priority < right.priority:
# We recursively reconstruct its left sub-tree
right.left = merge(left, right.left)
return right
raise RuntimeError("Unreachable")
```
### Insertion
Inserting a node into the tree is done in two steps:
1. `split` the tree to isolate the middle insertion point
2. `merge` it back up to form a full tree with the inserted key
```python
def insert(self, key: K, value: V) -> bool:
# `left` and `right` come before/after the key
left, node, right = split(self._root, key)
was_updated: bool
# Create the node, or update its value, if the key was already in the tree
if node is None:
node = Node(key, value)
was_updated = False
else:
node.value = value
was_updated = True
# Rebuild the tree with a couple of merge operations
self._root = merge(left, merge(node, right))
# Signal whether the key was already in the key
return was_updated
```
### Removal
Removing a key from the tree is similar to inserting a new key, and forgetting
to insert it back: simply `split` the tree and `merge` it back without the
extracted middle node.
```python
def remove(self, key: K) -> bool:
# `node` contains the key, or `None` if the key wasn't in the tree
left, node, right = split(self._root, key)
# Put the tree back together, without the extract node
self._root = merge(left, right)
# Signal whether `key` was mapped in the tree
return node is not None
```