Autocomplete System Using Trie in Go

A Trie (pronounced “try”) is a tree-like data structure that stores a dynamic set of strings, where the keys are usually strings. It is highly efficient for retrieval operations, such as searching for a word in a dictionary. In this implementation, we will use a Trie to design an autocomplete system that suggests words based on a given prefix.

Program Structure

The Go program implementing the autocomplete system using a Trie is structured into the following components:

  1. TrieNode Struct: This struct represents a node in the Trie, containing a map of child nodes and a boolean indicating if the node represents the end of a word.
  2. Trie Struct: This struct represents the Trie itself, containing the root node.
  3. Insert Method: This method inserts a word into the Trie.
  4. SearchPrefix Method: This method searches for the node corresponding to a given prefix in the Trie.
  5. Autocomplete Method: This method returns a list of all words in the Trie that start with a given prefix.
  6. CollectWords Method: This helper method recursively collects all words that can be formed from a given node in the Trie.

Go Code Implementation


package main

import "fmt"

// TrieNode represents a node in the Trie
type TrieNode struct {
    children map[rune]*TrieNode // Map of child nodes
    isEnd    bool               // Is true if the node represents the end of a word
}

// Trie represents the Trie structure
type Trie struct {
    root *TrieNode // Root node of the Trie
}

// NewTrie creates a new Trie
func NewTrie() *Trie {
    return &Trie{root: &TrieNode{children: make(map[rune]*TrieNode)}}
}

// Insert inserts a word into the Trie
func (t *Trie) Insert(word string) {
    node := t.root
    for _, char := range word {
        if _, exists := node.children[char]; !exists {
            node.children[char] = &TrieNode{children: make(map[rune]*TrieNode)}
        }
        node = node.children[char]
    }
    node.isEnd = true
}

// SearchPrefix searches for the node corresponding to the given prefix in the Trie
func (t *Trie) SearchPrefix(prefix string) *TrieNode {
    node := t.root
    for _, char := range prefix {
        if _, exists := node.children[char]; !exists {
            return nil
        }
        node = node.children[char]
    }
    return node
}

// Autocomplete returns a list of words in the Trie that start with the given prefix
func (t *Trie) Autocomplete(prefix string) []string {
    results := []string{}
    node := t.SearchPrefix(prefix)
    if node != nil {
        t.collectWords(node, prefix, &results)
    }
    return results
}

// collectWords recursively collects all words that can be formed from the given node
func (t *Trie) collectWords(node *TrieNode, prefix string, results *[]string) {
    if node.isEnd {
        *results = append(*results, prefix)
    }
    for char, childNode := range node.children {
        t.collectWords(childNode, prefix+string(char), results)
    }
}

func main() {
    // Create a new Trie and insert some words
    trie := NewTrie()
    words := []string{"apple", "app", "apricot", "banana", "band", "bandana", "bandit"}
    for _, word := range words {
        trie.Insert(word)
    }

    // Test the autocomplete function
    prefix := "ban"
    fmt.Printf("Autocomplete results for prefix '%s':\n", prefix)
    for _, word := range trie.Autocomplete(prefix) {
        fmt.Println(word)
    }
}
    

Explanation of the Code

Here’s a breakdown of the code:

  • TrieNode Struct: The TrieNode struct represents each node in the Trie. It contains a map of child nodes, where each key is a character, and a boolean isEnd that indicates if the node represents the end of a word.
  • Trie Struct: The Trie struct represents the Trie itself and contains the root node.
  • Insert Method: This method inserts a word into the Trie by iterating over each character in the word and creating the necessary child nodes if they don’t already exist.
  • SearchPrefix Method: This method searches for the node corresponding to a given prefix in the Trie. It returns the node if the prefix exists or nil if it doesn’t.
  • Autocomplete Method: This method returns a list of all words in the Trie that start with a given prefix. It first finds the node corresponding to the prefix using SearchPrefix and then collects all possible words from that node using collectWords.
  • CollectWords Method: This helper method recursively traverses the Trie from a given node, appending all complete words (where isEnd is true) to the results slice.

Usage Example

Here’s an example of how you might use this Trie-based autocomplete system in a Go program:


func main() {
    // Create a new Trie and insert some words
    trie := NewTrie()
    words := []string{"apple", "app", "apricot", "banana", "band", "bandana", "bandit"}
    for _, word := range words {
        trie.Insert(word)
    }

    // Test the autocomplete function
    prefix := "ban"
    fmt.Printf("Autocomplete results for prefix '%s':\n", prefix)
    for _, word := range trie.Autocomplete(prefix) {
        fmt.Println(word)
    }
}
    

Conclusion

This Go program demonstrates a basic implementation of an autocomplete system using a Trie data structure. Tries are highly efficient for prefix-based queries, making them ideal for applications like autocomplete, spell-checking, and dictionary implementations. The structure allows for fast insertion, search, and prefix-based word retrieval.

 

By Aditya Bhuyan

I work as a cloud specialist. In addition to being an architect and SRE specialist, I work as a cloud engineer and developer. I have assisted my clients in converting their antiquated programmes into contemporary microservices that operate on various cloud computing platforms such as AWS, GCP, Azure, or VMware Tanzu, as well as orchestration systems such as Docker Swarm or Kubernetes. For over twenty years, I have been employed in the IT sector as a Java developer, J2EE architect, scrum master, and instructor. I write about Cloud Native and Cloud often. Bangalore, India is where my family and I call home. I maintain my physical and mental fitness by doing a lot of yoga and meditation.

Leave a Reply

Your email address will not be published. Required fields are marked *

error

Enjoy this blog? Please spread the word :)