The Trie Explained In Ruby, Javascript and Python: Mastering Data Structures

A Deep Dive Into Tries With Three Popular Languages

Patrick Karsh
3 min readOct 5, 2023

A trie, often referred to as a prefix tree, is a hierarchical data structure commonly used to store a collection of strings. This unique data structure is highly optimized for searching, insertion, and deletion of words, making it ideal for applications like dictionaries, phone books, and text auto-completion.

Let’s dive deeper into the trie with practical examples in both Javascript(ES6), Ruby and Python.

The Basics of Trie

At its core, a trie consists of nodes where each node represents a single character of a string. Starting from the root, each path down the tree represents a word or a prefix. A special marker is used to indicate the end of a word.

Key Characteristics:

  1. Root Node: Represents an empty string.
  2. Children: Each node can have multiple children, corresponding to possible characters.
  3. Word End: A boolean or marker indicating the end of a word.

Implementing Trie in Javascript

class TrieNode {
constructor() {
this.children = {};
this.isEndOfWord = false;
}
}

class Trie {
constructor() {
this.root = new TrieNode();
}

insert(word) {
let currentNode = this.root;
for (let char of word) {
if (!currentNode.children[char]) {
currentNode.children[char] = new TrieNode();
}
currentNode = currentNode.children[char];
}
currentNode.isEndOfWord = true;
}

search(word) {
let currentNode = this.root;
for (let char of word) {
if (!currentNode.children[char]) {
return false;
}
currentNode = currentNode.children[char];
}
return currentNode.isEndOfWord;
}
}

const trie = new Trie();
trie.insert("apple");
trie.insert("appetite");
console.log(trie.search("apple")); // true
console.log(trie.search("app")); // false

Implementing Trie in Ruby

class TrieNode
attr_accessor :children, :is_end_of_word

def initialize
@children = {}
@is_end_of_word = false
end
end

class Trie
attr_accessor :root

def initialize
@root = TrieNode.new
end

def insert(word)
current_node = @root
word.each_char do |char|
current_node.children[char] ||= TrieNode.new
current_node = current_node.children[char]
end
current_node.is_end_of_word = true
end

def search(word)
current_node = @root
word.each_char do |char|
return false unless current_node.children[char]
current_node = current_node.children[char]
end
current_node.is_end_of_word
end
end

trie = Trie.new
trie.insert("apple")
trie.insert("appetite")
puts trie.search("apple") # true
puts trie.search("app") # false

Implementing Trie in Python

class TrieNode:
def __init__(self):
self.children = {}
self.is_end_of_word = False

class Trie:
def __init__(self):
self.root = TrieNode()

def insert(self, word):
current_node = self.root
for char in word:
if char not in current_node.children:
current_node.children[char] = TrieNode()
current_node = current_node.children[char]
current_node.is_end_of_word = True

def search(self, word):
current_node = self.root
for char in word:
if char not in current_node.children:
return False
current_node = current_node.children[char]
return current_node.is_end_of_word

# Example Usage:
trie = Trie()
trie.insert("apple")
trie.insert("appetite")
print(trie.search("apple")) # True
print(trie.search("app")) # False

Common Uses for Tries in Algorithm Interviews

Tries frequently appear in technical interviews, especially when dealing with string-based problems. Here are three common scenarios where tries shine during algorithm-type interviews:

Autocomplete: One of the classic applications for tries is to implement the autocomplete feature seen in search engines and messaging apps. Given a prefix, the candidate can be asked to retrieve all the possible completions. The trie data structure allows for efficient traversal of all the words sharing the same prefix.

Word Dictionary: Tries can be used to build an in-memory dictionary where insertion, deletion, and search operations for words are optimized. Interviewers often pose problems where candidates need to check the existence of a word or its derivatives in a given dictionary, and tries provide a suitable solution for such challenges.

Longest Common Prefix: Another typical interview problem involves finding the longest common prefix among a set of words. By inserting all the words into a trie and then traversing it, the depth at which the first branch occurs corresponds to the end of the longest common prefix.

Including trie-based questions in an interview setting not only tests the candidate’s knowledge of data structures but also their ability to apply them to real-world scenarios, showcasing their problem-solving skills and understanding of optimization techniques.

Conclusion

Tries offer a unique blend of efficient storage and search capabilities, especially when dealing with a large dataset of strings. Their tree-like structure is optimized to reduce redundancy and expedite searches, making them a go-to choice for several text-based applications.

--

--

Patrick Karsh
Patrick Karsh

Written by Patrick Karsh

NYC-based Ruby on Rails and Javascript Engineer leveraging AI to explore Engineering. https://linktr.ee/patrickkarsh

No responses yet