Swift: Efficient Autocomplete System using Trie in Swift - COFPROG

Swift: Efficient Autocomplete System using Trie in Swift

Problem Statement:

Imagine you're tasked with implementing an autocomplete system. Given a query string s and a set of all possible query strings, the goal is to return all strings in the set that have s as a prefix. For instance, given the query string "de" and the set of strings ["dog", "deer", "deal"], the autocomplete system should return ["deer", "deal"].

Introduction:

In today's digital age, autocomplete systems have become ubiquitous in various applications, from search engines to text editors. These systems provide users with suggestions based on the input query, enhancing user experience and productivity. In this blog post, we'll explore how to implement an efficient autocomplete system in Swift using the Trie data structure.

Approach:

To efficiently solve this problem, we'll leverage the Trie data structure. A Trie, also known as a prefix tree, is a tree-like data structure used for storing a dynamic set of strings. Each node in the Trie represents a single character of the string, and paths from the root to the leaf nodes represent valid words. Using a Trie allows for fast lookup of strings with a given prefix, making it an ideal choice for implementing autocomplete systems.

Implementation:

class TrieNode {

    var children: [Character: TrieNode]

    var isEndOfWordBool


    init() {

        self.children = [:]

        self.isEndOfWord = false

    }

}


class Trie {

    var root: TrieNode


    init() {

        self.root = TrieNode()

    }


    func insert(_ word: String) {

        var node = root

        for char in word {

            if node.children[char] == nil {

                node.children[char] = TrieNode()

            }

            node = node.children[char]!

        }

        node.isEndOfWord = true

    }


    func searchPrefix(_ prefix: String) -> TrieNode? {

        var node = root

        for char in prefix {

            if let nextNode = node.children[char] {

                node = nextNode

            } else {

                return nil

            }

        }

        return node

    }


    func findAllWords(_ node: TrieNode, _ prefix: String_ results: inout [String]) {

        if node.isEndOfWord {

            results.append(prefix)

        }

        for (char, child) in node.children {

            findAllWords(child, prefix + String(char), &results)

        }

    }

}


func autocomplete(_ query: String_ dictionary: [String]) -> [String] {

    let trie = Trie()

    for word in dictionary {

        trie.insert(word)

    }

    

    var results: [String] = []

    if let prefixNode = trie.searchPrefix(query) {

        trie.findAllWords(prefixNode, query, &results)

    }

    return results

}


// Example usage:

let query = "de"

let dictionary = ["dog""deer""deal"]

let autocompleteResults = autocomplete(querydictionary)

print(autocompleteResults// Output: ["deer", "deal"]


We'll start by defining a TrieNode class, representing each node in the Trie. Each node will have a dictionary to store its children nodes and a boolean flag indicating whether the node marks the end of a word.

Next, we'll define a Trie class responsible for Trie operations such as insertion, prefix search, and collecting all words below a given node. We'll implement methods to insert words into the Trie, search for nodes corresponding to a prefix, and collect all words with a given prefix using depth-first search.

Finally, we'll implement the autocomplete function, which takes a query string and a dictionary of strings as input. It constructs a Trie from the dictionary, searches for the prefix node corresponding to the query string, and collects all words below that node.

Example Usage:

Let's demonstrate the usage of our autocomplete system with an example. Suppose we have a query string "de" and a dictionary of strings ["dog", "deer", "deal"]. Using our autocomplete function, we can obtain the autocomplete suggestions ["deer", "deal"] for the query string "de".

Conclusion:

In this blog post, we explored how to implement an efficient autocomplete system in Swift using the Trie data structure. By preprocessing the dictionary into a Trie, we can quickly provide autocomplete suggestions for a given query string. This approach improves user experience by offering real-time suggestions and demonstrates the power of data structures in solving practical problems.

I hope this blog post has provided you with insights into implementing autocomplete systems and inspired you to explore more about data structures and algorithms in Swift. Happy coding!




Previous
Next Post »