Proofs: Trie
These are the human proofs of Trie, at full length.
The trie operations keep the invariant and answer the string symbol table queries full
This proof shows: correctness.
We use the pseudocode of the page. For a node , is the string spelled by the path from the root to . The invariant is:
(T1) is a key with value if and only if some node has and NIL. (T2) Each node other than the root has a value or a child. (T3) is the number of nodes with a value.
The edges out of one node carry distinct symbols, because is a function from symbols to nodes. This structural fact holds for each trie, and no operation can break it: a link is only written at an index where it was NIL (line L8), or removed (line L21).
Lemma 1 (walk). For a string , let be the largest such that some node has . Then this node is unique, and a walk from the root that follows visits the nodes of for and then stops (it finds a NIL link at step if ).
Proof. By induction on . For the walk is at the root, and the root is the only node with . Assume the walk is at the unique node with , and . A node with has a parent with , so by uniqueness, and the edge from to carries . The edges out of carry distinct symbols, so there is at most one such , and it is . If it exists, the walk moves to it; if not, the link is NIL and no node of exists, so .
GET. By Lemma 1, lines L1 to L4 return NIL exactly when no node has , and then is not a key by (T1). Else the loop ends at the unique node with , and line L5 returns . By (T1) this is the value of if is a key, and NIL if it is not. GET changes nothing.
PUT. Lines L6 to L9 visit, by Lemma 1, the nodes of the prefixes of that exist, and line L8 creates the missing ones, each as the only child for its symbol. At the end is the unique node with . New nodes have no value, and only the value of is changed. So (T1) holds: the keys other than keep their nodes and values, and now has the value NIL. Line L10 adds one to exactly when had no value, so (T3) holds. For (T2), each new node lies on the path from the root to , so it has a child on that path or it is , which has a value.
DELETE. If lines L13 to L17 return, then by Lemma 1 and (T1) is not a key, and nothing changed. Else the list holds the nodes with for , and has a value. Line L18 removes that value and subtracts one from , so (T1) and (T3) hold for the set of keys without . Now (T2) can fail only at nodes of . We show that the loop of lines L19 to L21 restores it. The loop keeps this claim, for the current : (T2) holds at each node except possibly , and the nodes that were cut had no value. At the start, and only changed. If line L20 finds that has a value or a child, (T2) holds everywhere and the loop returns. Else has no value and no child, so cutting the link to it removes one node and no key, and its parent is the only node whose children changed. So the claim holds for . If the loop reaches , it stops at the root, for which (T2) asks nothing. Cutting a node with no value keeps (T1) and (T3).
KEYS-WITH-PREFIX. Let be the node of found in line L22. If there is none, then by Lemma 1 no node has a string that starts with , because the node of each such string would have the node of as an ancestor. So no key starts with , and the empty list is right. Else, the stack always holds pairs : this holds for , and line L28 pushes . Each node of the subtree of is pushed exactly one time, because each node has one parent. Each node of the subtree has that starts with , and each node with such a string is in the subtree of . So by (T1), line L27 appends exactly the keys that start with , each one time.
Order. The loop is a preorder walk with the children of each node visited in increasing order of their symbols, because they are pushed in decreasing order onto a stack. In this order, comes before the strings of its subtree, which it is a proper prefix of, and for two children of a node, each string below comes before each string below . These are the two rules of lexicographic order, so the output is sorted.
LONGEST-PREFIX-OF. By Lemma 1, the loop visits the node of for each , where is as in the lemma, and stops after (by line L33 or line L35). The prefixes with have no node, so by (T1) they are not keys. For , line L32 sets exactly when is a key. Since increases, at the end is the largest such , or if there is none. Line L36 returns the longest prefix of that is a key, or NIL.
Termination and cost. Each loop of GET, PUT, DELETE and LONGEST-PREFIX-OF runs at most times. The loop of KEYS-WITH-PREFIX pops one node of the subtree of in each round and pushes each node one time, so it runs exactly times, where is the number of nodes of the subtree.