To Mike — Leftist Heap Start

Mike, I’ve been learning how to implement leftist heaps. I’ve been thinking about the primary merge function, and have the following implementation.

I define a node in my heap like this:

class Node:
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
        self.npl = 0

There is a value, a left and a right node, and an npl value.

Most heap nodes you’ll see have a value and left and right children. npl is a special property — it stands for Null Path Length. It’s the shortest path from X (the current node) to a null node — that is, a node with either one or no children.

I implemented a small function get_npl. It’s a minor convenience, but it makes access more explicit later in the algorithm:

def get_npl(node):
    return node.npl if node else -1

The merge function itself is a simple recursive function:

def merge(h1, h2):
    if not h1: return h2
    if not h2: return h1

    # Ensure h1 is the root with the smaller value; if not, swap.
    if h1.val > h2.val:
        h1, h2 = h2, h1

    # Recursive merge: h1's right child with h2.
    h1.right = merge(h1.right, h2)

    return finalize_node(h1)

I’ve been grappling with a good name for the “finalizing” function finalize_node. It could be maybe_swap, or swap_and_update_npl. It might swap the left and right nodes depending on the NPL, and then update the NPL. Here it is:

def finalize_node(node):
    # Compare NPLs: if right is longer, swap to keep it "left-heavy".
    if get_npl(node.left) < get_npl(node.right):
        node.left, node.right = node.right, node.left

    # Update current node's NPL based on the right child.
    node.npl = get_npl(node.right) + 1
    return node

This swapping is critical: it maintains the leftist property. By keeping the tree leftist, the merge can maintain O(log n) runtime, significantly faster than a naive O(n). It comes down to knowing the tree is always leftist, which eliminates traversals and speeds up merge performance.