diff --git a/DataStructures/Trie/Trie.php b/DataStructures/Trie/Trie.php index 32c8c6d..03b353a 100644 --- a/DataStructures/Trie/Trie.php +++ b/DataStructures/Trie/Trie.php @@ -1,8 +1,9 @@ root; for ($i = 0; $i < strlen($prefix); $i++) { $char = $prefix[$i]; diff --git a/DataStructures/Trie/TrieNode.php b/DataStructures/Trie/TrieNode.php index d9865f1..303da90 100644 --- a/DataStructures/Trie/TrieNode.php +++ b/DataStructures/Trie/TrieNode.php @@ -1,8 +1,9 @@ normalizeChar($char); if (!isset($this->children[$char])) { $this->children[$char] = new TrieNode(); } @@ -38,6 +40,7 @@ public function addChild(string $char): TrieNode */ public function hasChild(string $char): bool { + $char = $this->normalizeChar($char); return isset($this->children[$char]); } @@ -46,6 +49,15 @@ public function hasChild(string $char): bool */ public function getChild(string $char): ?TrieNode { + $char = $this->normalizeChar($char); return $this->children[$char] ?? null; } + + /** + * Normalize the character to lowercase. + */ + private function normalizeChar(string $char): string + { + return strtolower($char); + } } diff --git a/tests/DataStructures/TrieTest.php b/tests/DataStructures/TrieTest.php index 7733ed8..a8ab2cd 100644 --- a/tests/DataStructures/TrieTest.php +++ b/tests/DataStructures/TrieTest.php @@ -1,8 +1,9 @@ trie = new Trie(); } + /** + * Test insertion and search functionality of the Trie. + */ public function testInsertAndSearch() { $this->trie->insert('the'); @@ -42,6 +47,48 @@ public function testInsertAndSearch() ); } + /** + * Test insertion and search functionality with mixed case words. + */ + public function testInsertAndSearchMixedCase() + { + $this->trie->insert('Apple'); + $this->trie->insert('aPPle'); + $this->assertTrue($this->trie->search('apple'), 'Expected "apple" to be found in the Trie.'); + $this->assertTrue($this->trie->search('APPLE'), 'Expected "APPLE" to be found in the Trie.'); + } + + /** + * Test insertion and search functionality with special characters. + */ + public function testInsertAndSearchWithSpecialCharacters() + { + $this->trie->insert('hello123'); + $this->trie->insert('user@domain.com'); + $this->assertTrue($this->trie->search('hello123'), 'Expected "hello123" to be found in the Trie.'); + $this->assertTrue( + $this->trie->search('UseR@domain.CoM'), + 'Expected "user@domain.com" to be found in the Trie.' + ); + $this->assertTrue( + $this->trie->search('HELLO123'), + 'Expected "HELLO123" not to be found in the Trie (case-sensitive).' + ); + } + + /** + * Test insertion and search functionality with long strings. + */ + public function testInsertAndSearchLongStrings() + { + $longString = str_repeat('a', 1000); + $this->trie->insert($longString); + $this->assertTrue($this->trie->search($longString), 'Expected the long string to be found in the Trie.'); + } + + /** + * Test the startsWith functionality of the Trie. + */ public function testStartsWith() { $this->trie->insert('hello'); @@ -58,9 +105,31 @@ public function testStartsWith() ); } + /** + * Test startsWith functionality with mixed case prefixes. + */ + public function testStartsWithMixedCase() + { + $this->trie->insert('PrefixMatch'); + $this->trie->insert('PreFixTesting'); + $this->assertEquals( + ['prefixmatch', 'prefixtesting'], + $this->trie->startsWith('prefix'), + 'Expected words starting with "prefix" to be found in the Trie (case-insensitive).' + ); + + $this->assertEquals( + ['prefixmatch', 'prefixtesting'], + $this->trie->startsWith('PREFIX'), + 'Expected words starting with "PREFIX" to be found in the Trie (case-insensitive).' + ); + } + + /** + * Test deletion of existing words from the Trie. + */ public function testDelete() { - // Insert words into the Trie $this->trie->insert('the'); $this->trie->insert('universe'); $this->trie->insert('is'); @@ -80,12 +149,51 @@ public function testDelete() $this->assertTrue($this->trie->search('rather'), 'Expected "rather" to be found.'); } + /** + * Test deletion of mixed case words from the Trie. + */ + public function testDeleteMixedCase() + { + $this->trie->insert('MixedCase'); + $this->assertTrue($this->trie->search('mixedcase'), 'Expected "mixedcase" to be found before deletion.'); + + $this->trie->delete('MIXEDCASE'); + $this->assertFalse( + $this->trie->search('MixedCase'), + 'Expected "MixedCase" not to be found after deletion (case-insensitive).' + ); + } + + /** + * Test deletion of words with special characters. + */ + public function testDeleteWithSpecialCharacters() + { + $this->trie->insert('spec!@l#chars'); + $this->assertTrue( + $this->trie->search('spec!@l#chars'), + 'Expected "spec!@l#chars" to be found before deletion.' + ); + + $this->trie->delete('SPEC!@L#CHARS'); + $this->assertFalse( + $this->trie->search('spec!@l#chars'), + 'Expected "spec!@l#chars" not to be found after deletion.' + ); + } + + /** + * Test deletion of a non-existent word from the Trie. + */ public function testDeleteNonExistentWord() { $this->trie->delete('nonexistent'); $this->assertFalse($this->trie->search('nonexistent'), 'Expected "nonexistent" to not be found.'); } + /** + * Test traversal of the Trie and retrieval of words. + */ public function testTraverseTrieNode() { $this->trie->insert('hello'); @@ -99,11 +207,17 @@ public function testTraverseTrieNode() $this->assertCount(3, $words, 'Expected 3 words in the Trie.'); } + /** + * Test behavior of an empty Trie. + */ public function testEmptyTrie() { $this->assertEquals([], $this->trie->getWords(), 'Expected an empty Trie to return an empty array.'); } + /** + * Test retrieval of words from the Trie. + */ public function testGetWords() { $this->trie->insert('apple'); @@ -117,12 +231,18 @@ public function testGetWords() $this->assertCount(3, $words, 'Expected 3 words in the Trie.'); } + /** + * Test insertion of an empty string into the Trie. + */ public function testInsertEmptyString() { $this->trie->insert(''); $this->assertTrue($this->trie->search(''), 'Expected empty string to be found in the Trie.'); } + /** + * Test deletion of an empty string from the Trie. + */ public function testDeleteEmptyString() { $this->trie->insert(''); @@ -130,6 +250,9 @@ public function testDeleteEmptyString() $this->assertFalse($this->trie->search(''), 'Expected empty string not to be found after deletion.'); } + /** + * Test the startsWith functionality with a common prefix. + */ public function testStartsWithWithCommonPrefix() { $this->trie->insert('trie'); @@ -142,4 +265,38 @@ public function testStartsWithWithCommonPrefix() $this->assertContains('trier', $words, 'Expected "trier" to be found with prefix "tri".'); $this->assertCount(3, $words, 'Expected 3 words with prefix "tri".'); } + + /** + * Test retrieval of the root node of the Trie. + */ + public function testGetRoot() + { + $root = $this->trie->getRoot(); + $this->assertInstanceOf(TrieNode::class, $root, 'Expected root to be an instance of TrieNode.'); + $this->assertFalse($root->isEndOfWord, 'Expected the root node not to be the end of a word.'); + $this->assertCount(0, $root->children, 'Expected the root node to have no children initially.'); + } + + /** + * Test retrieval of the root node after populating the Trie with words. + */ + public function testGetRootAfterPopulation() + { + $this->trie->insert('TheAlgorithms'); + $this->trie->insert('PHP'); + $this->trie->insert('DSA'); + + $root = $this->trie->getRoot(); + + $this->assertInstanceOf(TrieNode::class, $root, 'Expected root to be an instance of TrieNode.'); + + // Assert that the root node is not marked as the end of a word + $this->assertFalse($root->isEndOfWord, 'Expected the root node not to be the end of a word.'); + + // Assert that the root node has children corresponding to the inserted words + $this->assertCount(3, $root->children, 'Expected the root node to have 3 children after inserting words.'); + $this->assertTrue($root->hasChild('t'), 'Expected root to have a child for "t".'); + $this->assertTrue($root->hasChild('p'), 'Expected root to have a child for "p".'); + $this->assertTrue($root->hasChild('D'), 'Expected root to have a child for "D".'); + } }