From 1627b633bd12d80fb9a732b691f8e5a9e147c0d3 Mon Sep 17 00:00:00 2001 From: Revone Date: Wed, 18 Oct 2023 17:05:38 +0800 Subject: [PATCH] [trie] getHeight returns faulty height bug fixed. Variables renamed for best practice --- src/data-structures/trie/trie.ts | 23 ++++--- test/unit/data-structures/trie/trie.test.ts | 74 ++++++++++++++++++++- 2 files changed, 86 insertions(+), 11 deletions(-) diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index 608aea5..1cb8cb8 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -6,8 +6,8 @@ * @license MIT License */ export class TrieNode { - constructor(v: string) { - this._key = v; + constructor(key: string) { + this._key = key; this._isEnd = false; this._children = new Map(); } @@ -63,7 +63,8 @@ export class Trie { set root(v: TrieNode) { this._root = v; } - private _caseSensitive: boolean; + + private readonly _caseSensitive: boolean; add(word: string): boolean { word = this._caseProcess(word); @@ -80,22 +81,24 @@ export class Trie { return true; } - has(input: string): boolean { - input = this._caseProcess(input); + has(word: string): boolean { + word = this._caseProcess(word); let cur = this.root; - for (const c of input) { + for (const c of word) { const nodeC = cur.children.get(c); if (!nodeC) return false; cur = nodeC; } return cur.isEnd; } + private _caseProcess(input: string) { if (!this._caseSensitive) { input = input.toLowerCase(); // Convert input to lowercase if case insensitive } return input; } + remove(word: string) { word = this._caseProcess(word); let isDeleted = false; @@ -131,7 +134,7 @@ export class Trie { getHeight() { const beginRoot = this.root; - let maxDepth = 1; + let maxDepth = 0; if (beginRoot) { const bfs = (node: TrieNode, level: number) => { if (level > maxDepth) { @@ -144,17 +147,18 @@ export class Trie { } } }; - bfs(beginRoot, 1); + bfs(beginRoot, 0); } return maxDepth; } + // --- start additional methods --- /** * The function checks if a given input string has an absolute prefix in a tree data structure.Only can present as a prefix, not a word * @param {string} input - The input parameter is a string that represents the input value for the function. * @returns a boolean value. */ - isAbsPrefix(input: string): boolean { + isPurePrefix(input: string): boolean { input = this._caseProcess(input); let cur = this.root; for (const c of input) { @@ -230,6 +234,7 @@ export class Trie { prefix = this._caseProcess(prefix); const words: string[] = []; let found = 0; + function dfs(node: TrieNode, word: string) { for (const char of node.children.keys()) { const charNode = node.children.get(char); diff --git a/test/unit/data-structures/trie/trie.test.ts b/test/unit/data-structures/trie/trie.test.ts index c9571e8..b5a3982 100644 --- a/test/unit/data-structures/trie/trie.test.ts +++ b/test/unit/data-structures/trie/trie.test.ts @@ -44,8 +44,8 @@ describe('Trie', () => { const trie = new Trie(); trie.add('apple'); trie.add('app'); - expect(trie.isAbsPrefix('appl')).toBe(true); - expect(trie.isAbsPrefix('apples')).toBe(false); + expect(trie.isPurePrefix('appl')).toBe(true); + expect(trie.isPurePrefix('apples')).toBe(false); }); it('should check if a string is a prefix', () => { @@ -753,3 +753,73 @@ describe('Trie', () => { expect(trie.getWords('air')).toEqual([]); }); }); + +describe('Trie more tests', () => { + let trie: Trie; + + beforeEach(() => { + trie = new Trie(); + }); + + test('Add and Find Words', () => { + trie.add('apple'); + trie.add('banana'); + expect(trie.has('apple')).toBe(true); + expect(trie.has('banana')).toBe(true); + expect(trie.has('cherry')).toBe(false); + }); + + test('Remove Words', () => { + trie.add('apple'); + trie.add('banana'); + expect(trie.remove('apple')).toBe(true); + expect(trie.has('apple')).toBe(false); + expect(trie.remove('cherry')).toBe(false); + }); + + test('Case Sensitivity', () => { + const caseInsensitiveTrie = new Trie(['apple', 'Banana'], false); + expect(caseInsensitiveTrie.has('APPLE')).toBe(true); + expect(caseInsensitiveTrie.has('banana')).toBe(true); + expect(caseInsensitiveTrie.has('Cherry')).toBe(false); + }); + + test('Pure Prefix Check', () => { + trie.add('apple'); + expect(trie.isPurePrefix('appl')).toBe(true); + expect(trie.isPurePrefix('apple')).toBe(false); + }); + + test('Prefix Check', () => { + trie.add('apple'); + expect(trie.isPrefix('app')).toBe(true); + expect(trie.isPrefix('ban')).toBe(false); + }); + + test('Common Prefix Check', () => { + trie.add('apple'); + trie.add('appetizer'); + expect(trie.isCommonPrefix('app')).toBe(true); + expect(trie.isCommonPrefix('apple')).toBe(false); + }); + + test('Longest Common Prefix', () => { + trie.add('apple'); + trie.add('appetizer'); + expect(trie.getLongestCommonPrefix()).toBe('app'); + }); + + test('Get Words by Prefix', () => { + trie.add('apple'); + trie.add('appetizer'); + trie.add('banana'); + const words = trie.getWords('app', 2); // Get at most 2 words with the prefix 'app' + expect(words).toEqual(['apple', 'appetizer']); + }); + + test('Tree Height', () => { + trie.add('apple'); + trie.add('banana'); + expect(trie.getHeight()).toBe(6); // Assuming 'apple' and 'banana' are the longest words. + }); +});