Now on to the more difficult modification operations.

How do we insert an element or update a value? Well, we can spider down to the place where the new node should live using the same algorithm as get above. But we can't just add the new node there if its (randomly chosen) priority is larger than its parent's. Instead, we have to move it upwards in the tree, while maintaining the ordering property of binary trees.

Well, I've already mentioned that tree rotation move nodes up and down and preserve ordering. So let's implement left and right rotations:

(def left-rotate (node) (Node node.left.p node.left.key node.left.val node.left.left (Node node.p node.key node.val node.left.right node.right))) (def right-rotate (node) (Node node.right.p node.right.key node.right.val (Node node.p node.key node.val node.left node.right.left) node.right.right))

With that out of the way, let's start on insertion itself.

First, we'll need to import the random module to get priorities:

(use random)

The new node needs a random priority before we inserted, and I'm going to pass that priority up and down the call stack instead of generating it once we get to the leaves of the tree. Trust me on this one.

With that set, here's a rough skeleton for set :

(def set (key val root #:(p (random.randint 0 1000000000))) ( cond ((not root) ?) ; Just generate the new node ((< key root.key) ?) ; Recurse leftwards, then do a left-rotation if necessary ((> key root.key) ?) ; Same as the (<) case, but recurse and rotate to the right ((= key root.key) ?))) ; Update existing node. So, just create the new node

Alright, let's fill this baby in. The first case, with an empty treap, is easy: [2 Note that #0 , the null object, is my representation of the null treap.]

((not root) (Node p key val #0 #0))

Next, let's do the last case, where we are updating a value, not adding a new key:

((= key root.key) (Node root.p root.key val root.left root.right))

Note that I'm not updating the priority; it would have been fine to do so, but would only have lead to extra tree rotations later.

We have only the two middle cases left, and they're basically identical. First, we recurse to insert into one of the subtrees. But that might have upset the heap property, so we may have to carry out the appropriate rotation:

((< key root.key) ( let (new (Node root.p root.key root.val (set key val root.left #:(p p)) root.right)) ( if (< new.left.p new.p) (left-rotate new) new))) ((> key root.key) ( let (new (Node root.p root.key root.val root.left (set key val root.right #:(p p)))) ( if (< new.right.p new.p) (right-rotate new) new)))

Putting it together, we have:

(def set (key val root #:(p (random.randint 0 1000000000))) ( cond ((not root) (Node p key val #0 #0)) ((< key root.key) ( let (new (Node root.p root.key root.val (set key val root.left #:(p p)) root.right)) ( if (< new.left.p new.p) (left-rotate new) new))) ((> key root.key) ( let (new (Node root.p root.key root.val root.left (set key val root.right #:(p p)))) ( if (< new.right.p new.p) (right-rotate new) new))) ((= key root.key) (Node root.p root.key val root.left root.right))))