5.2. Implementation

This section describes how to implement a trie.

Trie Node

Let us define a class, TrieNode:

public class TrieNode<T> {
    private final Map<Character, TrieNode<T>> children;
    private TrieNode<T> parent;
    private boolean end_state;
    private char key;
    private T value;

    public TrieNode(TrieNode<T> parent, char key) {
        children = new HashMap<>();
        setEndState(false);
        setParent(parent);
        setKey(key);
        setValue(null);
    }
}
  • L1: the generic type T represents the type of value in L6.

  • L2: Map is used to store the children.

  • L4: true if this node represents the last character of a certain word; otherwise, false.

  • L9: HashMap gives the O(1)O(1) complexity for searching a key.

What other types of maps are implemented in Java?

Let us define getter methods:

  • L10: returns the map consisting of children's characters as keys and their nodes as values.

Is there any risk of returning this.children in L11?

Let us then define setter methods:

  • L7: returns the previously assigned value of this node.

  • L13: returns the child with the specific key if exists; otherwise, a new child with the key.

What does the removeChild() method return if key does not exist in this node?

Finally, let us define checker methods:

  • L1: returns true if this node represents the last character of a certain word; false.

Trie

Let us create the class, Trie:

  • L1: defines a generic type T that can be any type.

  • L5: initializes the root with the null character.

Let us define the find() method that takes a specific key in string and returns the node corresponding the last character of the key:

  • L5: iterates through every character in the string.

  • L6: finds the node whose key is the current character.

  • L7: the child does not exist, implying that key is not introduced in this trie.

Given the find() method, let us define the get() method that takes a string key and returns the value of the node corresponding to the key in this trie:

  • L3: checks if both the key exists and the key is a word.

We then define the put() method that inserts a key-value pair to the trie:

  • L4-5: iterates through all characters in the key and adds children as necessary.

  • L7: sets the end state of the node corresponding the last character to true.

  • L8: returns the value of the previously key if exists; otherwise, null.

What does node.addChild(c) return if the child with the key c already exists?

The following demonstrates how the put() method works:

Finally, let us define the remove() method that removes all appropriate nodes corresponding to the key:

  • L2: retrieves the node corresponding to the last character in the key.

  • L4: returns false the key does not exist or the key is not a word.

  • L7-10: if the retrieved node has children, sets its end-state to false and returns true.

  • L12-23: removes ancestors who have descendants only related to this key.

The following demonstrates how the remove() method works:

Last updated

Was this helpful?