mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-12-26 07:01:18 +08:00
Add Trie.deleteWord and TrieNode.removeChild (#181)
This commit is contained in:
parent
6e2ff9b604
commit
d25eff49e6
@ -24,6 +24,35 @@ export default class Trie {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} word
|
||||
* @return {Trie}
|
||||
*/
|
||||
deleteWord(word) {
|
||||
function depthFirstDelete(currentNode, charIndex) {
|
||||
if (charIndex >= word.length) return;
|
||||
|
||||
const character = word[charIndex];
|
||||
const nextNode = currentNode.getChild(character);
|
||||
|
||||
if (nextNode == null) return;
|
||||
|
||||
depthFirstDelete(nextNode, charIndex + 1);
|
||||
|
||||
if (charIndex === word.length - 1) {
|
||||
nextNode.isCompleteWord = false;
|
||||
}
|
||||
|
||||
// childNode is deleted only if:
|
||||
// - childNode has NO children
|
||||
// - childNode.isCompleteWord === false
|
||||
currentNode.removeChild(character);
|
||||
}
|
||||
|
||||
depthFirstDelete(this.head, 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} word
|
||||
* @return {string[]}
|
||||
|
@ -37,6 +37,31 @@ export default class TrieNode {
|
||||
return childNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} character
|
||||
* @return {TrieNode}
|
||||
*/
|
||||
removeChild(character) {
|
||||
function isSafeToDelete(node) {
|
||||
return (
|
||||
node
|
||||
&& !node.isCompleteWord
|
||||
&& node.children.getKeys().length === 0
|
||||
);
|
||||
}
|
||||
|
||||
const childNode = this.getChild(character);
|
||||
|
||||
// delete childNode only if:
|
||||
// - childNode has NO children
|
||||
// - childNode.isCompleteWord === false
|
||||
if (isSafeToDelete(childNode)) {
|
||||
this.children.delete(character);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} character
|
||||
* @return {boolean}
|
||||
|
@ -23,6 +23,18 @@ describe('Trie', () => {
|
||||
expect(trie.head.getChild('c').getChild('a').getChild('t').toString()).toBe('t*');
|
||||
});
|
||||
|
||||
it('should delete words from trie', () => {
|
||||
const trie = new Trie();
|
||||
|
||||
trie.addWord('carpet');
|
||||
trie.addWord('car');
|
||||
expect(trie.doesWordExist('carpet')).toBe(true);
|
||||
|
||||
trie.deleteWord('carpet');
|
||||
expect(trie.doesWordExist('carpet')).toEqual(false);
|
||||
expect(trie.doesWordExist('car')).toEqual(true);
|
||||
});
|
||||
|
||||
it('should suggests next characters', () => {
|
||||
const trie = new Trie();
|
||||
|
||||
|
@ -18,6 +18,36 @@ describe('TrieNode', () => {
|
||||
expect(trieNode.toString()).toBe('c:a,o');
|
||||
});
|
||||
|
||||
describe('removing child nodes', () => {
|
||||
it('should delete child node if the child node has NO children', () => {
|
||||
const trieNode = new TrieNode('c');
|
||||
trieNode.addChild('a');
|
||||
expect(trieNode.hasChild('a')).toBe(true);
|
||||
|
||||
trieNode.removeChild('a');
|
||||
expect(trieNode.hasChild('a')).toBe(false);
|
||||
});
|
||||
|
||||
it('should NOT delete child node if the child node has children', () => {
|
||||
const trieNode = new TrieNode('c');
|
||||
trieNode.addChild('a');
|
||||
const childNode = trieNode.getChild('a');
|
||||
childNode.addChild('r');
|
||||
|
||||
trieNode.removeChild('a');
|
||||
expect(trieNode.hasChild('a')).toEqual(true);
|
||||
});
|
||||
|
||||
it('should NOT delete child node if the child node completes a word', () => {
|
||||
const trieNode = new TrieNode('c');
|
||||
const IS_COMPLETE_WORD = true;
|
||||
trieNode.addChild('a', IS_COMPLETE_WORD);
|
||||
|
||||
trieNode.removeChild('a');
|
||||
expect(trieNode.hasChild('a')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should get child nodes', () => {
|
||||
const trieNode = new TrieNode('c');
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user