Smart Search Autocomplete Engine

Project Overview & Use Case

The Use Case: When you type “py” into Google, it instantly suggests “python”, “python download”, “pycharm”, etc. Have you ever wondered how it does that so fast? If Google just stored billions of words in a standard Python List and checked each one, searching would take minutes.

The Solution: They use an advanced Data Structure called a Trie (pronounced “try”, also known as a Prefix Tree) combined with a Depth-First Search (DFS) algorithm.

The Output: This project builds a custom search engine for a dictionary of words. You type a prefix, and it uses a Trie to instantly predict and return all possible words you might be trying to type.

System Workflow (How It Works)

The Nodes: The system is built out of TrieNode objects. Each node represents a single letter (e.g., ‘a’). It also holds a dictionary of its child letters and a boolean flag (is_end_of_word) to mark if the current path forms a complete word.

Insertion (Building the Dictionary): When we add the word “CAT”, the system creates a root node, adds ‘C’ as a child, ‘A’ as a child of ‘C’, and ‘T’ as a child of ‘A’. It marks ‘T’ as the end of a word.

Prefix Traversal: When a user types “CA”, the system quickly walks down the tree to the ‘A’ node.

DFS (Finding Suggestions): From the ‘A’ node, the Depth-First Search algorithm explores every possible branch below it to find all nodes marked as is_end_of_word (e.g., finding “CAT”, “CAR”, “CATCH”) and returns them to the user.

Source Code

autocomplete.py

class TrieNode:
  """A single node in the Prefix Tree representing a single character."""
  def __init__(self):
      # A dictionary to store child nodes. Key: character, Value: TrieNode
      self.children = {}
      # Marks if this specific node represents the end of a valid dictionary word
      self.is_end_of_word = False

class AutocompleteSystem:
  """The main system that manages the Trie data structure and algorithms."""
  def __init__(self):
      # The root of the tree is always an empty node
      self.root = TrieNode()

  def insert_word(self, word):
      """DSA Concept: Inserting data into a Tree."""
      current_node = self.root
      
      # Traverse letter by letter
      for char in word.lower():
          # If the letter doesn't exist as a branch, create it
          if char not in current_node.children:
              current_node.children[char] = TrieNode()
          # Move down to the next node
          current_node = current_node.children[char]
          
      # We reached the end of the word, mark it as valid
      current_node.is_end_of_word = True

  def _dfs(self, node, current_prefix, suggestions):
      """
      DSA Concept: Depth-First Search (DFS) Algorithm.
      Recursively travels down the branches to find complete words.
      """
      # If the current node is a valid word, add it to our list
      if node.is_end_of_word:
          suggestions.append(current_prefix)
          
      # Explore all children of this node
      for char, child_node in node.children.items():
          self._dfs(child_node, current_prefix + char, suggestions)

  def get_suggestions(self, prefix):
      """Searches the Trie for a given prefix and triggers the DFS."""
      prefix = prefix.lower()
      current_node = self.root
      
      # Step 1: Navigate to the end of the user's prefix
      for char in prefix:
          if char not in current_node.children:
              # The prefix doesn't exist in our dictionary at all
              return [] 
          current_node = current_node.children[char]
          
      # Step 2: We found the prefix. Now use DFS to find all words branching from here
      suggestions = []
      self._dfs(current_node, prefix, suggestions)
      
      return suggestions

# --- Execution & User Interface ---
if __name__ == "__main__":
  print("⚙️ Booting up Autocomplete Engine...")
  engine = AutocompleteSystem()
  
  # 1. Create a dummy database of words
  database = [
      "python", "pycharm", "pypi", "programming", "program", 
      "project", "algorithm", "algo", "alien", "apple", "app",
      "data", "database", "structure", "software"
  ]
  
  print("📚 Loading dictionary into the Trie...")
  for word in database:
      engine.insert_word(word)
      
  print("
✅ System Ready!")
  print("Type a few letters to get suggestions (or type 'exit' to quit).")
  
  # 2. Interactive Loop
  while True:
      print("-" * 40)
      user_input = input("🔍 Search: ")
      
      if user_input.lower() == 'exit':
          print("Shutting down engine. Goodbye!")
          break
          
      if not user_input.strip():
          continue
          
      # Get suggestions using our DSA engine
      results = engine.get_suggestions(user_input)
      
      if results:
          print(f"💡 Suggestions: {', '.join(results)}")
      else:
          print("🚫 No suggestions found.")
  

Why this proves DSA is useful (The “Why”)

If you didn’t know DSA, you would probably just write code that loops through a massive list: [word for word in database if word.startswith(prefix)]

If your database has 1,000,000 words (like a real dictionary), checking every single word with .startswith() requires the computer to do massive amounts of unnecessary work.

By using the Trie Data Structure, the computer only looks at the exact letters you typed. If you type “app”, the computer takes exactly 3 steps to find the “p” node, and ignores the other 999,990 words entirely. This is why Google is fast, and this is why software engineers are tested on DSA!

Execution Guide

  • Create a file named autocomplete.py.

  • Paste the code above into the file.

  • Open your terminal and run python autocomplete.py.

  • Try typing p or py or app and watch the engine instantly fetch the related words based on the underlying graph structure.