Trie Delete - GeeksforGeeks

Trie Delete

Last Updated : 31 Oct, 2026

Given a Trie containing lowercase English words and a string key, delete the given key from the Trie. If the key is not present, the Trie should remain unchanged.

Examples:

Input: word[] = ["apple", "app", "apply", "bat"], key = "app"
Output: ["apple", "apply", "bat"]
Explanation: The word "app" is deleted from the Trie. The words "apple", "apply", and "bat" remain unchanged.

Input: word[] = ["cat", "car", "dog"], key = "dog"
Output: ["cat", "car"]
Explanation: The word "dog" is deleted from the Trie, while "cat" and "car" remain in the Trie.

Input: word[] = ["cat", "car"], key = "can"
Output: ["cat", "car"]
Explanation: The word "can" is not present in the Trie, so the Trie remains unchanged.

Try It Yourself
redirect icon

The key is deleted from the Trie using recursion in a bottom-up manner.

  • First, traverse the Trie to reach the last character of the key.
  • Set the isEndOfWord flag of the last node to false.
  • While returning from recursion, delete a node if it is not the end of another word and has no children.
  • Never delete the root node.

Consider a Trie containing ["car", "card", "care", "dog"].

file

The following cases explain the deletion process.

Case 1: Key is not present in the Trie

Suppose the key to delete is "can".

  • Traverse the Trie through c and a.
  • Since the node for n does not exist, the key is not present.
  • Return without modifying the Trie.

Thus, all words remain unchanged: ["car", "card", "care", "dog"].

Case 2: The key is a prefix of another word

Suppose the key to delete is "car".

  • Traverse the Trie to reach the last character r.
  • Set the isEndOfWord flag of node r to false.
  • Do not delete node r because it has children d and e, which are needed to form "card" and "care".
2056958743

Thus, the remaining words are ["card", "care", "dog"].

Case 3: Key shares a prefix with other words

Suppose the key to delete is "card".

  • Traverse the Trie to reach the last character d.
  • Set the isEndOfWord flag of node d to false.
  • Delete node d because it has no children and is not the end of another word.
  • Move backwards to node r. Retain it because it is needed by "car" and "care".
file

Thus, the remaining words are ["car", "care", "dog"].

Case 4: The key does not share its path with any other word

Suppose the key to delete is "dog".

  • Traverse the Trie to reach the last character g.
  • Set the isEndOfWord flag of node g to false.
  • Delete node g because it has no children.
  • Move backwards and delete nodes o and d because they are not needed by any other word.
  • Stop at the root, which is never deleted.
file

Thus, the remaining words are ["car", "card", "care"].

C++
#include <bits/stdc++.h>
using namespace std;

class TrieNode {
  public:
    TrieNode* children[26];
    bool isEndOfWord;

    TrieNode() {
        for (int i = 0; i < 26; i++) {
            children[i] = nullptr;
        }
        isEndOfWord = false;
    }
};

// Check whether a node has any children
bool isItFreeNode(TrieNode* node) {
    for (int i = 0; i < 26; i++) {
        if (node->children[i] != nullptr) {
            return false;
        }
    }
    return true;
}

// Recursively delete a key from the Trie
TrieNode* deleteHelper(TrieNode* node, string& key, int depth) {
    if (node == nullptr) {
        return nullptr;
    }

    // If we have reached the end of the key
    if (depth == (int)key.size()) {

        // Key is not present
        if (!node->isEndOfWord) {
            return node;
        }

        // Remove the end-of-word mark
        node->isEndOfWord = false;

        // Delete this node if it has no children
        if (depth != 0 && isItFreeNode(node)) {
            delete node;
            return nullptr;
        }

        return node;
    }

    int index = key[depth] - 'a';

    // Recursively delete the remaining characters
    node->children[index] = deleteHelper(
        node->children[index], key, depth + 1
    );

    // Delete the current node if it is no longer needed
    if (depth != 0 && !node->isEndOfWord && isItFreeNode(node)) {
        delete node;
        return nullptr;
    }

    return node;
}

void deleteKey(TrieNode* root, string key) {
    if (root == nullptr || key.empty()) {
        return;
    }

    deleteHelper(root, key, 0);
}

// Insert a key into the Trie
void insert(TrieNode* root, string key) {
    TrieNode* curr = root;

    for (char ch : key) {
        int index = ch - 'a';

        if (curr->children[index] == nullptr) {
            curr->children[index] = new TrieNode();
        }

        curr = curr->children[index];
    }

    curr->isEndOfWord = true;
}

// Search for a key in the Trie
bool search(TrieNode* root, string key) {
    TrieNode* curr = root;

    for (char ch : key) {
        int index = ch - 'a';

        if (curr->children[index] == nullptr) {
            return false;
        }

        curr = curr->children[index];
    }

    return curr->isEndOfWord;
}

int main() {
    
    // Create a Trie
    TrieNode* root = new TrieNode();

    // Insert keys into the Trie
    vector<string> words = {"car", "card", "care", "dog"};

    for (string word : words) {
        insert(root, word);
    }

    // Key to delete
    string key = "card";

    // Delete the given key
    deleteKey(root, key);

    // Print all words that remain in the Trie
    for (string w : words) {
        if (search(root, w)) {
            cout << w << " ";
        }
    }

    return 0;
}
Java
class TrieNode {
    TrieNode[] children;
    boolean isEndOfWord;

    TrieNode() {
        children = new TrieNode[26];
        isEndOfWord = false;
    }
}

public class GFG {

    // Check whether a node has any children
    static boolean isItFreeNode(TrieNode node) {
        for (int i = 0; i < 26; i++) {
            if (node.children[i] != null) {
                return false;
            }
        }
        return true;
    }

    // Recursively delete a key from the Trie
    static TrieNode deleteHelper(TrieNode node, String key, int depth) {
        if (node == null) {
            return null;
        }

        // If we have reached the end of the key
        if (depth == key.length()) {

            // Key is not present
            if (!node.isEndOfWord) {
                return node;
            }

            // Remove the end-of-word mark
            node.isEndOfWord = false;

            // Delete this node if it has no children
            if (depth != 0 && isItFreeNode(node)) {
                return null;
            }

            return node;
        }

        int index = key.charAt(depth) - 'a';

        // Recursively delete the remaining characters
        node.children[index] = deleteHelper(
            node.children[index], key, depth + 1
        );

        // Delete the current node if it is no longer needed
        if (depth != 0 && !node.isEndOfWord && isItFreeNode(node)) {
            return null;
        }

        return node;
    }

    static void deleteKey(TrieNode root, String key) {
        if (root == null || key.isEmpty()) {
            return;
        }

        deleteHelper(root, key, 0);
    }

    // Insert a key into the Trie
    static void insert(TrieNode root, String key) {
        TrieNode curr = root;

        for (char ch : key.toCharArray()) {
            int index = ch - 'a';

            if (curr.children[index] == null) {
                curr.children[index] = new TrieNode();
            }

            curr = curr.children[index];
        }

        curr.isEndOfWord = true;
    }

    // Search for a key in the Trie
    static boolean search(TrieNode root, String key) {
        TrieNode curr = root;

        for (char ch : key.toCharArray()) {
            int index = ch - 'a';

            if (curr.children[index] == null) {
                return false;
            }

            curr = curr.children[index];
        }

        return curr.isEndOfWord;
    }

    public static void main(String[] args) {

        // Create a Trie
        TrieNode root = new TrieNode();

        // Insert keys into the Trie
        String[] words = {"car", "card", "care", "dog"};

        for (String word : words) {
            insert(root, word);
        }

        // Key to delete
        String key = "card";

        // Delete the given key
        deleteKey(root, key);

        // Print all words that remain in the Trie
        for (String w : words) {
            if (search(root, w)) {
                System.out.print(w + " ");
            }
        }
    }
}
Python
class TrieNode:
    def __init__(self):
        self.children = [None] * 26
        self.isEndOfWord = False


# Check whether a node has any children
def isItFreeNode(node):
    for i in range(26):
        if node.children[i] is not None:
            return False
    return True


# Recursively delete a key from the Trie
def deleteHelper(node, key, depth):
    if node is None:
        return None

    # If we have reached the end of the key
    if depth == len(key):

        # Key is not present
        if not node.isEndOfWord:
            return node

        # Remove the end-of-word mark
        node.isEndOfWord = False

        # Delete this node if it has no children
        if depth != 0 and isItFreeNode(node):
            return None

        return node

    index = ord(key[depth]) - ord('a')

    # Recursively delete the remaining characters
    node.children[index] = deleteHelper(
        node.children[index], key, depth + 1
    )

    # Delete the current node if it is no longer needed
    if depth != 0 and not node.isEndOfWord and isItFreeNode(node):
        return None

    return node


def deleteKey(root, key):
    if root is None or not key:
        return

    deleteHelper(root, key, 0)


# Insert a key into the Trie
def insert(root, key):
    curr = root

    for ch in key:
        index = ord(ch) - ord('a')

        if curr.children[index] is None:
            curr.children[index] = TrieNode()

        curr = curr.children[index]

    curr.isEndOfWord = True


# Search for a key in the Trie
def search(root, key):
    curr = root

    for ch in key:
        index = ord(ch) - ord('a')

        if curr.children[index] is None:
            return False

        curr = curr.children[index]

    return curr.isEndOfWord


if __name__ == "__main__":

    # Create a Trie
    root = TrieNode()

    # Insert keys into the Trie
    words = ["car", "card", "care", "dog"]

    for word in words:
        insert(root, word)

    # Key to delete
    key = "card"

    # Delete the given key
    deleteKey(root, key)

    # Print all words that remain in the Trie
    for w in words:
        if search(root, w):
            print(w, end=" ")
C#
using System;

class TrieNode {
    public TrieNode[] children;
    public bool isEndOfWord;

    public TrieNode() {
        children = new TrieNode[26];
        isEndOfWord = false;
    }
}

class GFG {

    // Check whether a node has any children
    static bool isItFreeNode(TrieNode node) {
        for (int i = 0; i < 26; i++) {
            if (node.children[i] != null) {
                return false;
            }
        }
        return true;
    }

    // Recursively delete a key from the Trie
    static TrieNode deleteHelper(TrieNode node, string key, int depth) {
        if (node == null) {
            return null;
        }

        // If we have reached the end of the key
        if (depth == key.Length) {

            // Key is not present
            if (!node.isEndOfWord) {
                return node;
            }

            // Remove the end-of-word mark
            node.isEndOfWord = false;

            // Delete this node if it has no children
            if (depth != 0 && isItFreeNode(node)) {
                return null;
            }

            return node;
        }

        int index = key[depth] - 'a';

        // Recursively delete the remaining characters
        node.children[index] = deleteHelper(
            node.children[index], key, depth + 1
        );

        // Delete the current node if it is no longer needed
        if (depth != 0 && !node.isEndOfWord && isItFreeNode(node)) {
            return null;
        }

        return node;
    }

    static void deleteKey(TrieNode root, string key) {
        if (root == null || string.IsNullOrEmpty(key)) {
            return;
        }

        deleteHelper(root, key, 0);
    }

    // Insert a key into the Trie
    static void insert(TrieNode root, string key) {
        TrieNode curr = root;

        foreach (char ch in key) {
            int index = ch - 'a';

            if (curr.children[index] == null) {
                curr.children[index] = new TrieNode();
            }

            curr = curr.children[index];
        }

        curr.isEndOfWord = true;
    }

    // Search for a key in the Trie
    static bool search(TrieNode root, string key) {
        TrieNode curr = root;

        foreach (char ch in key) {
            int index = ch - 'a';

            if (curr.children[index] == null) {
                return false;
            }

            curr = curr.children[index];
        }

        return curr.isEndOfWord;
    }

    static void Main(string[] args) {

        // Create a Trie
        TrieNode root = new TrieNode();

        // Insert keys into the Trie
        string[] words = {"car", "card", "care", "dog"};

        foreach (string word in words) {
            insert(root, word);
        }

        // Key to delete
        string key = "card";

        // Delete the given key
        deleteKey(root, key);

        // Print all words that remain in the Trie
        foreach (string w in words) {
            if (search(root, w)) {
                Console.Write(w + " ");
            }
        }
    }
}
JavaScript
class TrieNode {
    constructor() {
        this.children = new Array(26).fill(null);
        this.isEndOfWord = false;
    }
}

// Check whether a node has any children
function isItFreeNode(node) {
    for (let i = 0; i < 26; i++) {
        if (node.children[i] !== null) {
            return false;
        }
    }
    return true;
}

// Recursively delete a key from the Trie
function deleteHelper(node, key, depth) {
    if (node === null) {
        return null;
    }

    // If we have reached the end of the key
    if (depth === key.length) {

        // Key is not present
        if (!node.isEndOfWord) {
            return node;
        }

        // Remove the end-of-word mark
        node.isEndOfWord = false;

        // Delete this node if it has no children
        if (depth !== 0 && isItFreeNode(node)) {
            return null;
        }

        return node;
    }

    let index = key.charCodeAt(depth) - 97;

    // Recursively delete the remaining characters
    node.children[index] = deleteHelper(
        node.children[index], key, depth + 1
    );

    // Delete the current node if it is no longer needed
    if (depth !== 0 && !node.isEndOfWord && isItFreeNode(node)) {
        return null;
    }

    return node;
}

function deleteKey(root, key) {
    if (root === null || key.length === 0) {
        return;
    }

    deleteHelper(root, key, 0);
}

// Insert a key into the Trie
function insert(root, key) {
    let curr = root;

    for (let ch of key) {
        let index = ch.charCodeAt(0) - 97;

        if (curr.children[index] === null) {
            curr.children[index] = new TrieNode();
        }

        curr = curr.children[index];
    }

    curr.isEndOfWord = true;
}

// Search for a key in the Trie
function search(root, key) {
    let curr = root;

    for (let ch of key) {
        let index = ch.charCodeAt(0) - 97;

        if (curr.children[index] === null) {
            return false;
        }

        curr = curr.children[index];
    }

    return curr.isEndOfWord;
}

// Driver code
let root = new TrieNode();

// Insert keys into the Trie
let words = ["car", "card", "care", "dog"];

for (let word of words) {
    insert(root, word);
}

// Key to delete
let key = "card";

deleteKey(root, keyToDelete);

// Print all words that remain in the Trie
for (let w of words) {
    if (search(root, w)) {
        process.stdout.write(w + " ");
    }
}

Output
car care dog 

Time Complexity: O(n), where n is the length of the key. Each character is visited once during the deletion process.

Auxiliary Space: O(n), due to the recursive call stack, where n is the length of the key.

Comment