Implementing a Radix Tree (Patricia Trie) in JavaScript
Radix trees, also known as Patricia tries, are a space-optimized form of trie data structure. They are particularly useful for storing and retrieving strings with common prefixes, offering improved performance and reduced memory usage compared to standard tries. This challenge asks you to implement a radix tree in JavaScript, focusing on efficient string storage and retrieval.
Problem Description
You are tasked with creating a JavaScript class called RadixTree that implements a radix tree data structure. The tree should support the following operations:
insert(str, value): Inserts a stringstrinto the tree with an associatedvalue. If the string already exists, the value should be updated.search(str): Searches for a stringstrin the tree. If found, it returns the associatedvalue; otherwise, it returnsundefined.remove(str): Removes a stringstrfrom the tree. If the string is not found, the function should do nothing.startsWith(prefix): Checks if any string in the tree starts with the givenprefix. Returnstrueif any string starts with the prefix,falseotherwise.
The tree should be implemented efficiently, minimizing memory usage by merging nodes with single children whenever possible. The internal node structure should be optimized for string comparisons.
Key Requirements:
- The tree should handle empty strings correctly.
- The tree should be case-sensitive.
- The
insertoperation should merge nodes with single children to optimize space. - The
removeoperation should also merge nodes after deletion to maintain the optimized structure. - The
startsWithoperation should efficiently check for prefixes.
Examples
Example 1:
Input:
tree = new RadixTree();
tree.insert("hello", 1);
tree.insert("helloworld", 2);
tree.insert("hell", 3);
Output:
tree.search("hello") // 1
tree.search("helloworld") // 2
tree.search("hell") // 3
tree.search("world") // undefined
Explanation: The tree is populated with three strings and their associated values. The search function correctly retrieves the values for existing strings and returns undefined for non-existent strings.
Example 2:
Input:
tree = new RadixTree();
tree.insert("test", 10);
tree.insert("tester", 20);
tree.insert("testing", 30);
tree.remove("tester");
Output:
tree.search("test") // 10
tree.search("tester") // undefined
tree.search("testing") // 30
tree.startsWith("test") // true
tree.startsWith("tes") // true
tree.startsWith("testing") // true
tree.startsWith("world") // false
Explanation: Demonstrates insertion, removal, and the startsWith functionality. Removal of "tester" doesn't affect "test" or "testing".
Example 3: (Edge Case - Empty String)
Input:
tree = new RadixTree();
tree.insert("", 5);
tree.insert("a", 1);
Output:
tree.search("") // 5
tree.search("a") // 1
tree.startsWith("") // true
tree.startsWith("a") // true
Explanation: Handles the edge case of inserting and searching for an empty string.
Constraints
- The input strings
strwill consist of lowercase English letters (a-z). - The
valueassociated with each string can be any JavaScript data type. - The maximum length of any string will be 1000 characters.
- The number of insertions and deletions will be less than 10000.
- The
startsWithoperation should complete in O(k) time, where k is the length of the prefix.
Notes
- Consider using a Node class to represent nodes in the radix tree. Each node should store a prefix string, a value (optional), and an array of child nodes.
- When inserting, carefully consider how to merge nodes with single children to optimize space.
- When removing, ensure that the tree structure remains optimized after deletion. This might involve merging nodes.
- Think about how to efficiently implement the
startsWithoperation by traversing the tree based on the prefix. - Pay attention to edge cases, such as inserting empty strings or removing strings that don't exist.
- The efficiency of your implementation will be judged based on both time and space complexity.