Trie

Context: FIT2004_MOC Β· string retrieval in independent of β€” a -ary Tree branching on characters; the base structure that suffix tries and trees specialise Parent Framework: Tree

Quick Revision

  • 🎯 Objective: one child slot per alphabet character one for the terminal $ βž” insert/search walk one edge per character ⟹ , and a $-first in-order DFS lists every word sorted in .
  • πŸ“¦ Core Components: links = [None]*27 βž” child lookup | payload data βž” counts, frequencies, scores | iterative aux vs recursive aux.
  • ⚑ Key Constraint: without $ a prefix is indistinguishable from a word β€” insert apple, and app β€œexists”. Every inserted word and every search key ends in $, and $ sits at links[0].

πŸ“ How It Works

1. Structure β€” Children and the Terminal $

  • BST vs trie βž” a BST has children (left/right); a trie has β€” the charset size: a..z Β· a..zA..Z Β· DNA (A,C,G,T).
  • for $ βž” apple$ means apple is stored; app reaching a node with no $ child is only a prefix. Searching tar in {taco, taro, tarot, coco, chobo} walks t-a-r successfully and fails on $ ⟹ not found.
  • $ at links[0] βž” $ sorts before every letter, so a $-first in-order walk emits app before apple β€” consistent with sorting. Map a , z .
  • Fixed-size array, not a list/dict βž” index character ⟹ child lookup is for a constant charset. Cost: the slots are mostly None ⟹ wasted space.
  • Payload βž” whatever the query needs (frequency, top- words, prefix count) β€” keep it small, since there is one per node and a trie has many nodes.
  • Edge vs node labels βž” the character properly lives on the edge (consistent with graph representation); labels drawn in nodes are also accepted in the exam.

2. Operations β€” Every Traversal Starts at the Root

  • Insert βž” for each character of word$: child exists ⟹ move to it Β· missing ⟹ create it, then move.
  • Search βž” for each character of key$: child exists ⟹ move Β· missing ⟹ return False / raise. Worst , best (first character absent).
  • Full traversal βž” in-order DFS over links[0..26] visits every node once ⟹ the stored words in alphabetical order in ( total characters incl. $); with words of length that is .
  • Iterative vs recursive βž” same time; iterative is aux, recursive aux (stack depth key length). Recursion is preferred when information must flow back up (subtree counts, best leaf below, flags) β€” iteration needs a second loop or an explicit stack.
  • Delete βž” not required at this level.

3. Properties β€” β€œUse the Properties to Explain Complexity”

words, longest letters, total characters including every $.

  • Nodes βž” ⟹ ; tighter ⟹ (root one node per character, when no prefixes are shared).
  • Leaves βž” β€” every leaf is a $ node. Maximum, because duplicates end at the same $ leaf.
  • Height βž” exactly edges root-to-deepest-leaf β€” the $ edge counts.
  • Lecture example βž” {taco, taro, tarot, coco, chobo}: , nodes (shared ta, tar, c), leaves, height (tarot$).
  • Prep P1 βž” {cat, cathode, canopy, dog, danger, domain}: , nodes, inner, leaves, height (cathode$). The t node branches into $ and h β€” a stored word that is also a prefix keeps its own $ child.

4. Augmented Tries β€” Applied P1, P2, P5, P7

  • P1 distinct strings in βž” insert all with $, count $ nodes; equal strings end at the same node.
  • P2 count words with prefix in βž” a counter in every node, +1 on every node moved to or created during insert ⟹ node.data number of words through it; query walk , return the count. Build cost unchanged. Rejected: walk then count leaves below ⟹ up to .
  • P7 most powerful prefix in βž” add to each node on insert; answer max-score node. baby, bank, bit ⟹ , , .
  • P5 predecessor in (output-sensitive) βž” walk the query, remembering the deepest node with a child smaller than the next character; on success return the query; on failure jump back there, take its greatest smaller child, then follow the greatest child to a leaf. No such node ⟹ null βž” trace below.

5. A Trie as an Accelerator [D] β€” Applied P10–P12

  • P10 max in βž” store the -bit integers MSB-first in a binary trie; at each level prefer the child with the opposite bit to (a in a high position beats every lower bit), else take the only child.
  • P11 max subarray XOR in βž” with prefix XOR (, associativity); for each query the trie of with , then insert ⟹ same move as Maximum Subarray Sum’s prefix sums.
  • P12 word break βž” the Dynamic Programming loop β€œevery that is a prefix of ” is one trie walk of ; each node with a $ child is a word ⟹ candidate . Build walks of .

βš™οΈ Core Implementation

πŸ”Ή Lecture Node / Trie insert, search, prefix count, sorted output

βš–οΈ Complexity

OperationTimeAux spaceNote
Insert one word iterative · recursive new nodes ⟹ space added
Searchbest Β· worst iterative query length, never appears
Build words nodeseach node holds a -slot array
Sorted listing stack outputin-order, $ first
Prefix count (P2)counter maintained during insert
Predecessor (P5) length of the answer

βš–οΈ Core Decision Matrix

strings, length ; one string comparison costs .

StructureBuildSearchPrefix / ordered queriesTrade-off
Sorted array Binary Search merge Β· radixyes, by range comparisons, each
BST / AVL balancedyessame -per-comparison tax
Hash Table expected expectedno β€” hashing destroys order and prefixescollisions ⟹ not deterministic; can be faster in practice
Trie deterministicyes β€” prefix a node, in-order sortedwasted None slots in every node

When It Flips: need only exact membership and memory is tight βž” Hash Table. The query mentions a prefix, an order (sorted, predecessor, lexicographic -th), or demands a worst-case bound βž” trie.

πŸ“Š Exam Execution Trace & Applied Exercises

Manual Execution Trace β€” P5 predecessor of candelabra

Trie of canada, canal, candid, candy, cart. ancestor deepest node with a child the character being followed.

StepCharNode’s childrenChild char?ancestor / ancestor_childanswer
1croot: cnoβ€”c
2ac: anoβ€”ca
3nca: n,rnoβ€”can
4dcan: a,da dcan / acand
5ecand: i,ynocan / ano e child ⟹ break
6back uppop to canβ€”β€”can cana
7greatest pathcana: d,l ⟹ l, then $β€”β€”canal

Final Extracted Output: canal. cand is not stored as an ancestor because both its children exceed e. Query ba on {aaa, aba, baa} returns aba; query baa returns itself.

⚠️ Common Mistakes

  • πŸ’‘ Forgetting the $ edge in the height βž” height is , not .
  • πŸ’‘ β€œLeaves ” βž” leaves ; duplicates share one $ leaf β€” exactly the fact P1 exploits.
  • πŸ’‘ Quoting search as or βž” a trie never compares whole strings; its cost depends on the query length only.
  • πŸ’‘ Counting a whole subtree per prefix query βž” ; push the count into the node at insert time (P2).

🧠 Active Recall