Deleting a word from a Trie is a bit more complex than inserting or searching. This is because we must ensure that we only remove the nodes that are no longer required by other words. To do this, we use a recursive approach that checks whether a node is part of any other word before removing it.
Approach and Steps
We define a recursive function deleteWord(node, word, index) that traverses the Trie from the root node.
- If we reach the end of the word (i.e.,
index === word.length), we check if the word actually exists in the Trie.
- If it exists, we unset the
is_end_of_word flag. If this node has no children, we tell the parent it can safely remove this node.
- As we return back up the recursive call stack, we check each node to see if its child (just deleted) can be removed, and if so, we remove it from the current node’s children.
- At each level, we check if the current node is still useful: it must either have children or be marked as an end of another word. If not, it can also be deleted.
Example: Deleting "ant" from a Trie
Let’s assume we have already inserted the words: ["app", "apple", "and", "ant", "danger", "dance"] into the Trie.
- We call
deleteWord(root, "ant", 0).
- The function navigates through each character:
'a' → 'n' → 't'.
- At node
't', we unmark is_end_of_word = false.
- We check if
't' has any children — it doesn't, so it can be deleted from its parent 'n'.
- Next, we check
'n' — since it's still used by the word "and", we do not delete 'n'.
- The word
"ant" is deleted, but the shared nodes needed by "and" are preserved.
Case 1 – Deleting a word that exists and has unique path
Example: Trie contains ["cat", "dog"], and we delete "dog".
- Traversal goes
'd' → 'o' → 'g'.
- 'g' is end of word and has no children → deleted.
- 'o' now has no children → deleted.
- 'd' now has no children → deleted.
- The entire branch "dog" is removed from the Trie.
Case 2 – Deleting a word that is a prefix for another word
Example: Trie contains ["bat", "batch"], and we delete "bat".
- Traversal reaches
't' and unmarks it as end of word.
- 't' has a child ('c' from "batch") → node must not be deleted.
- Only the
is_end_of_word flag is updated, structure remains.
Case 3 – Trying to delete a word that does not exist
Example: Trie contains ["cat", "car"], and we try to delete "can".
- Traversal fails at node 'n', which doesn't exist under 'a'.
- Function returns false, and Trie remains unchanged.
Case 4 – Deleting a word from an empty Trie
Example: Trie is empty, and we try to delete the word "apple".
- Since the root has no children, traversal stops immediately.
- Return false, no changes made.
Case 5 – Deleting the only word in the Trie
Example: Trie contains ["run"], and we delete "run".
- Each node is unmarked and deleted from leaf to root.
- After deletion, the Trie becomes empty again.