How to implement text Autocomplete feature using Ternary Search Tree (original) (raw)

Last Updated : 15 Jul, 2025

Given a set of strings S and a string patt the task is to autocomplete the string patt to strings from S that have patt as a prefix, using a Ternary Search Tree. If no string matches the given prefix, print "None".
Examples:

Input: S = {"wallstreet", "geeksforgeeks", "wallmart", "walmart", "waldomort", "word"],
patt = "wall"
Output:
wallstreet
wallmart
Explanation:
Only two strings {"wallstreet", "wallmart"} from S matches with the given pattern "wall".
Input: S = {"word", "wallstreet", "wall", "wallmart", "walmart", "waldo", "won"}, patt = "geeks"
Output: None
Explanation:
Since none of word of set matches with pattern so empty list will be printed.

Trie Approach: Please refer this article to learn about the implementation using Trie data structure.
Ternary Search Tree Approach Follow the steps below to solve the problem:

Below is the implementation of the above approach:

C++ `

// C++ Program to generate // autocompleted texts from // a given prefix using a // Ternary Search Tree #include <bits/stdc++.h> using namespace std;

// Define the Node of the // tree struct Node {

// Store the character
// of a string
char data;
// Store the end of
// word
int end;
// Left Subtree
struct Node* left;

// Equal Subtree
struct Node* eq;

// Right Subtree
struct Node* right;

};

// Function to create a Node Node* createNode(char newData) { struct Node* newNode = new Node(); newNode->data = newData; newNode->end = 0; newNode->left = NULL; newNode->eq = NULL; newNode->right = NULL; return newNode; }

// Function to insert a word // in the tree void insert(Node** root, string word, int pos = 0) {

// Base case
if (!(*root))
    *root = createNode(word[pos]);

// If the current character is
// less than root's data, then
// it is inserted in the
// left subtree

if ((*root)->data > word[pos])
    insert(&((*root)->left), word,
        pos);

// If current character is
// more than root's data, then
// it is inserted in the right
// subtree

else if ((*root)->data < word[pos])
    insert(&((*root)->right), word,
        pos);

// If current character is same
// as that of the root's data

else {
    // If it is the end of word

    if (pos + 1 == word.size())
        // Mark it as the
        // end of word
        (*root)->end = 1;

    // If it is not the end of
    // the string, then the
    // current character is
    // inserted in the equal subtree

    else
        insert(&((*root)->eq), word, pos + 1);
}

}

// Function to traverse the ternary search tree void traverse(Node* root, vector& ret, char* buff, int depth = 0) { // Base case if (!root) return; // The left subtree is // traversed first traverse(root->left, ret, buff, depth);

// Store the current character
buff[depth] = root->data;

// If the end of the string
// is detected, store it in
// the final ans
if (root->end) {
    buff[depth + 1] = '\0';
    ret.push_back(string(buff));
}

// Traverse the equal subtree
traverse(root->eq, ret,
        buff, depth + 1);

// Traverse the right subtree
traverse(root->right, ret,
        buff, depth);

}

// Utility function to find // all the words vector util(Node* root, string pattern) { // Stores the words // to suggest char buffer[1001];

vector<string> ret;

traverse(root, ret, buffer);

if (root->end == 1)
    ret.push_back(pattern);
return ret;

}

// Function to autocomplete // based on the given prefix // and return the suggestions vector autocomplete(Node* root, string pattern) { vector words; int pos = 0;

// If pattern is empty
// return an empty list
if (pattern.empty())
    return words;

// Iterating over the characters
// of the pattern and find it's
// corresponding node in the tree

while (root && pos < pattern.length()) {

    // If current character is smaller
    if (root->data > pattern[pos])
        // Search the left subtree
        root = root->left;

    // current character is greater
    else if (root->data < pattern[pos])
        // Search right subtree
        root = root->right;

    // If current character is equal
    else if (root->data == pattern[pos]) {
    
        // Search equal subtree
        // since character is found, move to the next character in the pattern
        root = root->eq;
        pos++;
    }

    // If not found
    else
        return words;

}

// Search for all the words
// from the current node
words = util(root, pattern);

return words;

}

// Function to print // suggested words

void print(vector sugg, string pat) { for (int i = 0; i < sugg.size(); i++) cout << pat << sugg[i].c_str() << "\n"; }

// Driver Code int main() { vector S = { "wallstreet", "geeksforgeeks", "wallmart", "walmart", "waldormort", "word" };

Node* tree = NULL;

// Insert the words in the
// Ternary Search Tree
for (string str : S)
    insert(&tree, str);

string pat = "wall";

vector<string> sugg
    = autocomplete(tree, pat);

if (sugg.size() == 0)
    cout << "None";

else
    print(sugg, pat);

return 0;

}

Python3

Python Program to generate

autocompleted texts from

a given prefix using a

Ternary Search Tree

Define the Node of the

tree

class Node:

# Store the character
# of a string
def __init__(self, newData):
    self.data = newData
    # Store the end of
    # word
    self.end = 0
    # Left Subtree
    self.left = None
    
    # Equal Subtree
    self.eq = None
    
    # Right Subtree
    self.right = None

Function to create a Node

Function to create a Node

def createNode(newData): newNode = Node(newData) newNode.end = 0 newNode.left = None newNode.eq = None newNode.right = None return newNode

Function to insert a word

in the tree

def insert(root, word, pos = 0):

# Base case
if not root:
    root = createNode(word[pos])

# If the current character is
# less than root's data, then
# it is inserted in the
# left subtree
if root.data > word[pos]:
    root.left = insert(root.left, word, pos)

# If current character is
# more than root's data, then
# it is inserted in the right
# subtree
elif root.data < word[pos]:
    root.right = insert(root.right, word, pos)

# If current character is same
# as that of the root's data
else:
    # If it is the end of word
    if pos + 1 == len(word):
        # Mark it as the
        # end of word
        root.end = 1
    # If it is not the end of
    # the string, then the
    # current character is
    # inserted in the equal subtree
    else:
        root.eq = insert(root.eq, word, pos + 1)
return root

Function to traverse the ternary search tree

def traverse(root, ret, buff, depth = 0):

# Base case
if not root:
    return

# The left subtree is
# traversed first
traverse(root.left, ret, buff, depth)

# Store the current character
buff[depth] = root.data

# If the end of the string
# is detected, store it in
# the final ans
if root.end:
    buff[depth + 1] = '\0'
    ret.append("".join(buff[:depth + 1]))

# Traverse the equal subtree
traverse(root.eq, ret, buff, depth + 1)

# Traverse the right subtree
traverse(root.right, ret, buff, depth)

Utility function to find

all the words

def util(root, pattern):

# Stores the words
# to suggest
buffer = [None] * 1001

ret = []

traverse(root, ret, buffer)

if root.end == 1:
    ret.append(pattern)
return ret

Function to autocomplete

based on the given prefix

and return the suggestions

def autocomplete(root, pattern): words = [] pos = 0

# If pattern is empty
# return an empty list
if not pattern:
    return words

# Iterating over the characters
# of the pattern and find it's
# corresponding node in the tree
while root and pos < len(pattern):
    # If current character is smaller
    if root.data > pattern[pos]:
        # Search the left subtree
        root = root.left
    
    # current character is greater
    elif root.data < pattern[pos]:
        # Search right subtree
        root = root.right
        
    # If current character is equal
    elif root.data == pattern[pos]:
        # Search equal subtree
        # since character is found, move to the next character in the pattern
        root = root.eq
        pos += 1
        
    # If not found
    else:
        return words

# Search for all the words
# from the current node
words = util(root, pattern)

return words

Function to print

suggested words

def print_suggestions(sugg, pat): for sug in sugg: print(pat + sug)

Driver Code

if name == 'main': S = ['wallstreet', 'geeksforgeeks', 'wallmart', 'walmart', 'waldormort', 'word'] tree = None

# Insert the words in the
# Ternary Search Tree
for str in S:
    tree = insert(tree, str)

pat = 'wall'
sugg = autocomplete(tree, pat)

if not sugg:
    print('None')
else:
    print_suggestions(sugg, pat)

This code is contributed by Utkarsh Kumar

C#

// C# Program to generate // autocompleted texts from // a given prefix using a // Ternary Search Tree

using System; using System.Collections.Generic;

namespace TernarySearchTree { public class TernarySearchTree { // Define the Node of the // tree private class Node { public char Value { get; set; } // Store the end of // word public bool IsEndOfWord { get; set; } // Left Subtree public Node Left { get; set; } // Equal Subtree public Node Middle { get; set; } // Right Subtree public Node Right { get; set; } }

private Node _root;

public void Insert(string word)
{
    _root = Insert(_root, word, 0);
}

// Function to insert a word
// in the tree
private Node Insert(Node node, string word, int index)
{
    // Base case
    if (node == null) {
        node = new Node{ Value = word[index] };
    }
    // If the current character is
    // less than root's data, then
    // it is inserted in the
    // left subtree
    if (word[index] < node.Value) {
        node.Left = Insert(node.Left, word, index);
    }
    // If current character is
    // more than root's data, then
    // it is inserted in the right
    // subtree
    else if (word[index] > node.Value) {
        node.Right = Insert(node.Right, word, index);
    }
    else {
        if (index < word.Length - 1) {
            node.Middle
                = Insert(node.Middle, word, index + 1);
        }
        else {
            node.IsEndOfWord = true;
        }
    }

    return node;
}

public List<string> AutoComplete(string prefix)
{
    var results = new List<string>();
    var node = FindNode(prefix);
    // Base case
    if (node != null) {
        if (node.IsEndOfWord) {
            results.Add(prefix);
        }

        Traverse(node.Middle, prefix, results);
    }

    return results;
}

private Node FindNode(string prefix)
{
    var node = _root;
    var index = 0;

    while (node != null && index < prefix.Length) {
        if (prefix[index] < node.Value) {
            node = node.Left;
        }
        else if (prefix[index] > node.Value) {
            node = node.Right;
        }
        else {
            index++;

            if (index < prefix.Length) {
                node = node.Middle;
            }
        }
    }

    return node;
}
// Traversing
private void Traverse(Node node, string prefix,
                      List<string> results)
{
    if (node != null) {
        Traverse(node.Left, prefix, results);

        var newPrefix = prefix + node.Value;

        if (node.IsEndOfWord) {
            results.Add(newPrefix);
        }

        Traverse(node.Middle, newPrefix, results);
        Traverse(node.Right, prefix, results);
    }
}

} // Driver Code class Program { static void Main(string[] args) { // Insert the words in the // Ternary Search Tree var t = new TernarySearchTree(); t.Insert("wallstreet"); t.Insert("geeksforgeeks"); t.Insert("wallmart"); t.Insert("walmart"); t.Insert("waldormort"); t.Insert("word");

    var results = t.AutoComplete("wall");
    foreach(var r in results) { Console.WriteLine(r); }
}

} } // Code is contributed by Narasinga Nikhil

JavaScript

// JavaScript Program for the above approach

// Define the Node of the tree class Node {

// Store the character of a string constructor(newData) { this.data = newData;

// Store the end of word
this.end = 0;

// Left Subtree
this.left = null;

// Equal Subtree
this.eq = null;

// Right Subtree
this.right = null;

} }

// Function to create a Node function createNode(newData) { const newNode = new Node(newData); newNode.end = 0; newNode.left = null; newNode.eq = null; newNode.right = null; return newNode; }

// Function to insert a word in the tree function insert(root, word, pos = 0) {

// Base case if (!root) { root = createNode(word[pos]); }

// If the current character is less than root's data, // then it is inserted in the left subtree if (root.data > word[pos]) { root.left = insert(root.left, word, pos); }

// If current character is more than root's data, // then it is inserted in the right subtree else if (root.data < word[pos]) { root.right = insert(root.right, word, pos); }

// If current character is same as that of the root's data else {

// If it is the end of word
if (pos + 1 === word.length)
{

  // Mark it as the end of word
  root.end = 1;
}

// If it is not the end of the string, then the 
// current character is inserted in the equal subtree
else {
  root.eq = insert(root.eq, word, pos + 1);
}

} return root; }

// Function to traverse the ternary search tree function traverse(root, ret, buff, depth = 0) { // Base case if (!root) { return; }

// The left subtree is traversed first traverse(root.left, ret, buff, depth);

// Store the current character buff[depth] = root.data;

// If the end of the string is detected, store it in the final ans if (root.end) { buff[depth + 1] = '\0'; ret.push(buff.slice(0, depth + 1).join("")); }

// Traverse the equal subtree traverse(root.eq, ret, buff, depth + 1);

// Traverse the right subtree traverse(root.right, ret, buff, depth); }

// Utility function to find all the words function util(root, pattern) {

// Stores the words to suggest const buffer = Array.from({ length: 1001 }, () => null); const ret = []; traverse(root, ret, buffer); if (root.end === 1) { ret.push(pattern); } return ret; }

// Function to autocomplete // based on the given prefix // and return the suggestions function autocomplete(root, pattern) { let words = []; let pos = 0;

// If pattern is empty // return an empty list if (!pattern) { return words; }

// Iterating over the characters // of the pattern and find it's // corresponding node in the tree while (root && pos < pattern.length) {

// If current character is smaller
if (root.data > pattern[pos])
{

  // Search the left subtree
  root = root.left;
}

// current character is greater
else if (root.data < pattern[pos])
{

  // Search right subtree
  root = root.right;
}

// If current character is equal
else if (root.data === pattern[pos]) 
{

  // Search equal subtree
  // since character is found, move to 
  // the next character in the pattern
  root = root.eq;
  pos += 1;
}
// If not found
else {
  return words;
}

}

// Search for all the words // from the current node words = util(root, pattern);

return words; }

// Function to print // suggested words function printSuggestions(sugg, pat) { for (let sug of sugg) { console.log(pat + sug); } }

// Driver Code let S = ['wallstreet', 'geeksforgeeks', 'wallmart', 'walmart', 'waldormort', 'word']; let tree = null;

// Insert the words in the // Ternary Search Tree for (let str of S) { tree = insert(tree, str); }

let pat = 'wall'; let sugg = autocomplete(tree, pat);

if (!sugg) { console.log('None'); } else { printSuggestions(sugg, pat); }

// This code is contributed by codebraxnzt

Java

// java Program to generate // autocompleted texts from // a given prefix using a // Ternary Search Tree

// The TSTNode class defines the nodes of the tree. class TSTNode { char data; boolean isEndOfWord; TSTNode left, middle, right;

public TSTNode(char data)
{
    this.data = data;
    this.isEndOfWord = false;
    this.left = null;
    this.middle = null;
    this.right = null;
}

}

// The TernarySearchTree class defines the tree itself class TernarySearchTree { TSTNode root;

public TernarySearchTree() { this.root = null; }

public void insert(String word)
{
    root = insert(root, word.toCharArray(), 0);
}

// The insert() method inserts a given string into the
// tree recursively.
private TSTNode insert(TSTNode node, char[] word,
                       int index)
{
    if (node == null) {
        node = new TSTNode(word[index]);
    }

    if (word[index] < node.data) {
        node.left = insert(node.left, word, index);
    }
    else if (word[index] > node.data) {
        node.right = insert(node.right, word, index);
    }
    else {
        if (index + 1 < word.length) {
            node.middle
                = insert(node.middle, word, index + 1);
        }
        else {
            node.isEndOfWord = true;
        }
    }
    return node;
}

public void autoComplete(String prefix)
{
    TSTNode node = searchPrefix(prefix);
    if (node == null) {
        System.out.println(
            "No words found with given prefix");
        return;
    }

    if (node.isEndOfWord) {
        System.out.println(prefix);
    }

    traverse(node.middle, new StringBuilder(prefix));
}
// The searchPrefix() method searches for a given prefix
// in the tree.
private TSTNode searchPrefix(String prefix)
{
    TSTNode node = root;
    int i = 0;
    while (node != null && i < prefix.length()) {
        if (prefix.charAt(i) < node.data) {
            node = node.left;
        }
        else if (prefix.charAt(i) > node.data) {
            node = node.right;
        }
        else {
            i++;
            if (i == prefix.length()) {
                return node;
            }
            node = node.middle;
        }
    }
    return node;
}

private void traverse(TSTNode node,
                      StringBuilder prefix)
{
    if (node == null) {
        return;
    }

    traverse(node.left, prefix);

    if (node.isEndOfWord) {
        System.out.println(prefix.toString()
                           + node.data);
    }

    traverse(node.middle, prefix.append(node.data));
    prefix.deleteCharAt(prefix.length() - 1);

    traverse(node.right, prefix);
}

} // Driver code public class Main { public static void main(String[] args) { String[] words = { "wallstreet", "geeksforgeeks", "wallmart", "walmart", "waldomort", "word" }; String prefix = "wall";

    TernarySearchTree tst = new TernarySearchTree();
    for (String word : words) {
        tst.insert(word);
    }

    System.out.println("Words with prefix " + prefix
                       + " are:");
    tst.autoComplete(prefix);
}

}

`

Output

wallmart wallstreet

Time Complexity: O(L* log N) where L is length of longest word.
The space is proportional to the length of the string to be stored.
Auxiliary Space: O(N)