mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-12-26 23:21:18 +08:00
Cleanup.
This commit is contained in:
parent
86a4069e26
commit
b7675f8834
@ -9,6 +9,7 @@
|
|||||||
3. [Stack](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/stack)
|
3. [Stack](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/stack)
|
||||||
4. [Hash Table](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/hash-table)
|
4. [Hash Table](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/hash-table)
|
||||||
5. [Heap](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/heap)
|
5. [Heap](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/heap)
|
||||||
|
5. [Trie](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/trie)
|
||||||
|
|
||||||
## [Algorithms](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms)
|
## [Algorithms](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms)
|
||||||
|
|
||||||
|
45
src/data-structures/trie/Trie.js
Normal file
45
src/data-structures/trie/Trie.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import TrieNode from './TrieNode';
|
||||||
|
|
||||||
|
const HEAD_CHARACTER = '*';
|
||||||
|
|
||||||
|
export default class Trie {
|
||||||
|
constructor() {
|
||||||
|
this.head = new TrieNode(HEAD_CHARACTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
addWord(word) {
|
||||||
|
const characters = Array.from(word);
|
||||||
|
let currentNode = this.head;
|
||||||
|
for (let charIndex = 0; charIndex < characters.length; charIndex += 1) {
|
||||||
|
const isComplete = charIndex === characters.length - 1;
|
||||||
|
currentNode = currentNode.addChild(characters[charIndex], isComplete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suggestNextCharacters(word) {
|
||||||
|
const lastCharacter = this.getLastCharacterNode(word);
|
||||||
|
|
||||||
|
if (!lastCharacter) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastCharacter.suggestChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
doesWordExists(word) {
|
||||||
|
return !!this.getLastCharacterNode(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLastCharacterNode(word) {
|
||||||
|
const characters = Array.from(word);
|
||||||
|
let currentNode = this.head;
|
||||||
|
for (let charIndex = 0; charIndex < characters.length; charIndex += 1) {
|
||||||
|
if (!currentNode.hasChild(characters[charIndex])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
currentNode = currentNode.getChild(characters[charIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentNode;
|
||||||
|
}
|
||||||
|
}
|
39
src/data-structures/trie/TrieNode.js
Normal file
39
src/data-structures/trie/TrieNode.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
export default class TrieNode {
|
||||||
|
constructor(character, isCompleteWord = false) {
|
||||||
|
this.character = character;
|
||||||
|
this.isCompleteWord = isCompleteWord;
|
||||||
|
this.children = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
getChild(character) {
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(this.children, character)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.children[character];
|
||||||
|
}
|
||||||
|
|
||||||
|
addChild(character, isCompleteWord = false) {
|
||||||
|
if (!this.children[character]) {
|
||||||
|
this.children[character] = new TrieNode(character, isCompleteWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.children[character];
|
||||||
|
}
|
||||||
|
|
||||||
|
hasChild(character) {
|
||||||
|
return !!this.children[character];
|
||||||
|
}
|
||||||
|
|
||||||
|
suggestChildren() {
|
||||||
|
return Object.keys(this.children);
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
let childrenAsString = Object.keys(this.children).toString();
|
||||||
|
childrenAsString = childrenAsString ? `:${childrenAsString}` : '';
|
||||||
|
const isCompleteString = this.isCompleteWord ? '*' : '';
|
||||||
|
|
||||||
|
return `${this.character}${isCompleteString}${childrenAsString}`;
|
||||||
|
}
|
||||||
|
}
|
51
src/data-structures/trie/__test__/Trie.test.js
Normal file
51
src/data-structures/trie/__test__/Trie.test.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import Trie from '../Trie';
|
||||||
|
|
||||||
|
describe('Trie', () => {
|
||||||
|
it('should create trie', () => {
|
||||||
|
const trie = new Trie();
|
||||||
|
|
||||||
|
expect(trie).toBeDefined();
|
||||||
|
expect(trie.head.toString()).toBe('*');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add words to trie', () => {
|
||||||
|
const trie = new Trie();
|
||||||
|
|
||||||
|
trie.addWord('cat');
|
||||||
|
|
||||||
|
expect(trie.head.toString()).toBe('*:c');
|
||||||
|
expect(trie.head.getChild('c').toString()).toBe('c:a');
|
||||||
|
|
||||||
|
trie.addWord('car');
|
||||||
|
expect(trie.head.toString()).toBe('*:c');
|
||||||
|
expect(trie.head.getChild('c').toString()).toBe('c:a');
|
||||||
|
expect(trie.head.getChild('c').getChild('a').toString()).toBe('a:t,r');
|
||||||
|
expect(trie.head.getChild('c').getChild('a').getChild('t').toString()).toBe('t*');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should suggests next characters', () => {
|
||||||
|
const trie = new Trie();
|
||||||
|
|
||||||
|
trie.addWord('cat');
|
||||||
|
trie.addWord('cats');
|
||||||
|
trie.addWord('car');
|
||||||
|
trie.addWord('caption');
|
||||||
|
|
||||||
|
expect(trie.suggestNextCharacters('ca')).toEqual(['t', 'r', 'p']);
|
||||||
|
expect(trie.suggestNextCharacters('cat')).toEqual(['s']);
|
||||||
|
expect(trie.suggestNextCharacters('cab')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check if word exists', () => {
|
||||||
|
const trie = new Trie();
|
||||||
|
|
||||||
|
trie.addWord('cat');
|
||||||
|
trie.addWord('cats');
|
||||||
|
trie.addWord('car');
|
||||||
|
trie.addWord('caption');
|
||||||
|
|
||||||
|
expect(trie.doesWordExists('cat')).toBeTruthy();
|
||||||
|
expect(trie.doesWordExists('cap')).toBeTruthy();
|
||||||
|
expect(trie.doesWordExists('call')).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
51
src/data-structures/trie/__test__/TrieNode.test.js
Normal file
51
src/data-structures/trie/__test__/TrieNode.test.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import TrieNode from '../TrieNode';
|
||||||
|
|
||||||
|
describe('TrieNode', () => {
|
||||||
|
it('should create trie node', () => {
|
||||||
|
const trieNode = new TrieNode('c', true);
|
||||||
|
|
||||||
|
expect(trieNode.character).toBe('c');
|
||||||
|
expect(trieNode.isCompleteWord).toBeTruthy();
|
||||||
|
expect(trieNode.toString()).toBe('c*');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add child nodes', () => {
|
||||||
|
const trieNode = new TrieNode('c');
|
||||||
|
|
||||||
|
trieNode.addChild('a', true);
|
||||||
|
trieNode.addChild('o');
|
||||||
|
|
||||||
|
expect(trieNode.toString()).toBe('c:a,o');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get child nodes', () => {
|
||||||
|
const trieNode = new TrieNode('c');
|
||||||
|
|
||||||
|
trieNode.addChild('a');
|
||||||
|
trieNode.addChild('o');
|
||||||
|
|
||||||
|
expect(trieNode.getChild('a').toString()).toBe('a');
|
||||||
|
expect(trieNode.getChild('o').toString()).toBe('o');
|
||||||
|
expect(trieNode.getChild('b')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check if node has specific child', () => {
|
||||||
|
const trieNode = new TrieNode('c');
|
||||||
|
|
||||||
|
trieNode.addChild('a');
|
||||||
|
trieNode.addChild('o');
|
||||||
|
|
||||||
|
expect(trieNode.hasChild('a')).toBeTruthy();
|
||||||
|
expect(trieNode.hasChild('o')).toBeTruthy();
|
||||||
|
expect(trieNode.hasChild('b')).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should suggest next children', () => {
|
||||||
|
const trieNode = new TrieNode('c');
|
||||||
|
|
||||||
|
trieNode.addChild('a');
|
||||||
|
trieNode.addChild('o');
|
||||||
|
|
||||||
|
expect(trieNode.suggestChildren()).toEqual(['a', 'o']);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user