```
type alias Rank = Int
type Heap a = E | T Rank a (Heap a) (Heap a)
```

The rank `r`

of a leftist heap is the length of its rightmost spine (that is, the number of edges on the path to the rightmost `E`

mpty node, or the number of non-`E`

nodes along this path).

The node `T r i left right`

stores its rank `r`

so that the `rank`

function below does not need to call `computeRank`

to recompute it.

```
computeRank : Heap -> Rank
computeRank h =
case h of
E -> 0
T r _ left right ->
if r == (1 + computeRank right)
then r
else Debug.crash "incorrect rank"
rank h =
case h of
E -> 0
T r _ _ _ -> r
```

A few functions on leftist heaps that we will use to state invariants:

```
value h =
case h of
E -> Nothing
T _ x _ _ -> Just x
left h =
case h of
E -> E
T _ _ a _ -> a
right h =
case h of
E -> E
T _ _ _ b -> b
size h =
case h of
E -> 0
T _ _ a b -> 1 + size a + size b
```

- Min-Heap Property:
*∀*`h`

. (`left(h)`

≠`E`

⇒`value(h)`

≤`value(left(h))`

) ∧ (`right(h)`

≠`E`

⇒`value(h)`

≤`value(right(h))`

) - Leftist Heap Rank Property:
*∀*`h`

.`rank(left(h))`

≥`rank(right(h))`

**In-Class Exercise**

- Prove:
*∀*`h`

.`size(h)`

≥`2^rank(h) - 1`

- Corollary:
*∀*. That is, the right spine of a leftist heap`h`

.`rank(h)`

is O(`log(size(h))`

)`h`

of size`n`

has*O(*elements.`log n`

)

Unlike for regular min-heaps, merging leftist heaps runs quickly (faster than *O(n)*) by taking advantage of the fact that right spines are short (*O(log n)*).

The helper function `makeT`

creates a `T`

node that stores `x`

and positions `h1`

and `h2`

as its children depending on their rank.

```
makeT : a -> Heap a -> Heap a -> Heap a
makeT x h1 h2 =
let (r1,r2) = (rank h1, rank h2) in
if r1 >= r2
then T (1+r2) x h1 h2
else T (1+r1) x h2 h1
```

The following is an equivalent definition of `makeT`

.

```
makeT x h1 h2 =
let (left,right) =
if rank h1 >= rank h2
then (h1, h2)
else (h2, h1)
in
T (1 + rank right) x left right
```

The `merge`

function combines two non-empty heaps by choosing the smaller of their two minimum values and recursively merging, using `makeT`

to place “heavier” subtrees to the left.

```
merge : Heap comparable -> Heap comparable -> Heap comparable
merge h1 h2 = case (h1, h2) of
(_, E) -> h1
(E, _) -> h2
(T _ x1 left1 right1, T _ x2 left2 right2) ->
if x1 <= x2
then makeT x1 left1 (merge right1 h2)
else makeT x2 left2 (merge h1 right2)
```

The `makeT`

function runs in *O(1)* time. The running time of `merge`

is dominated by its recursive calls. Let *n* be the size of the larger of the two heaps. The leftist property ensures that the right spine of each heap has *O(log n)* elements. Because the recursive calls traverse the right spine of one of the input heaps, there are at most *O(log n)* recursive calls, each of which performs *O(1)* work. Therefore, `merge`

runs in *O(log n)* time.

```
empty : Heap comparable
empty = E
isEmpty : Heap comparable -> Bool
isEmpty h = h == empty
findMin : Heap comparable -> Maybe comparable
findMin h =
case h of
E -> Nothing
T _ x _ _ -> Just x
```

Insertion and deletion can be defined in terms of `merge`

, so each runs in *O(log n)* time.

```
insert : comparable -> Heap comparable -> Heap comparable
insert x h = merge (T 1 x E E) h
deleteMin : Heap comparable -> Maybe (comparable, Heap comparable)
deleteMin h =
case h of
E -> Nothing
T _ x a b -> Just (x, merge a b)
```

Our implementation (`LeftistHeap.elm`

) exports the same type signatures as the array-based implementation of min-heaps from before.

```
module LeftistHeaps exposing
(Heap, empty, isEmpty, findMin, insert, deleteMin, merge)
...
```

Take it for a quick spin:

```
> import LeftistHeap exposing (..)
> makeHeap = List.foldl insert empty
<function> : List comparable -> LeftistHeap.Heap comparable
> makeHeap (String.toList "abcd")
T 2 'a' (T 1 'b' E E) (T 1 'c' (T 1 'd' E E) E) : LeftistHeap.Heap Char
> makeHeap (String.toList "dcba")
T 1 'a' (T 1 'b' (T 1 'c' (T 1 'd' E E) E) E) E : LeftistHeap.Heap Char
```

- Okasaki, Chapter 3.1