Skip to content

Commit

Permalink
Enhanced Trie Data Structure with Case-Insensitive Feature and additi…
Browse files Browse the repository at this point in the history
…onal Test Cases (#172)

* Added Disjoint Sets Data structure

* Moved DisjointSetTest.php to  tests/DataStructures

* Update DataStructures/DisjointSets/DisjointSet.php

Co-authored-by: Brandon Johnson <[email protected]>

* Update DataStructures/DisjointSets/DisjointSetNode.php

Co-authored-by: Brandon Johnson <[email protected]>

* Update DataStructures/DisjointSets/DisjointSetNode.php

Co-authored-by: Brandon Johnson <[email protected]>

* Update tests/DataStructures/DisjointSetTest.php

Co-authored-by: Brandon Johnson <[email protected]>

* Update tests/DataStructures/DisjointSetTest.php

Co-authored-by: Brandon Johnson <[email protected]>

* Update tests/DataStructures/DisjointSetTest.php

Co-authored-by: Brandon Johnson <[email protected]>

* Considered PHPCS remarks. Unit Testing is now working.

* Remove data type mixed. Considered annotations for php7.4.

* Remove data type mixed. Considered annotations for php7.4.

* updating DIRECTORY.md

* Implemented Trie DataStructure

* Added Trie to DIRECTORY.md

* updating DIRECTORY.md

* Implemented AVLTree DataStructure

* updating DIRECTORY.md

* Implemented AVLTree DataStructure

* Implemented SegmentTreeNode.php

* Implementing SegmentTree

* Implementing SegmentTree with updateTree

* Implementing SegmentTree with rangeUpdateTree

* Implementing SegmentTree with query and queryTree

* Added serializing and deserializing of the SegmentTree

* Adding unit tests SegmentTree implementation

* Added unit tests for SegmentTree updates and range updates

* considering PHPCS for Added unit tests for SegmentTree updates and range updates

* Added unit tests for SegmentTree serialization/deserialization and array updates reflections

* Added unit tests for SegmentTree  Edge Cases

* Added unit tests for SegmentTree Exceptions (OutOfBoundsException, InvalidArgumentException)

* Added SegmentTree to DIRECTORY.md

* Implemented Segment Tree Data Structure

* updating DIRECTORY.md

* Added some comments to my files in: #160, #162, #163, #166. Implemented Segment Tree Data Structure.

* Added some comments to my files in: #160, #162, #163, #166. Implemented Segment Tree Data Structure.

* Added comments time complexity for query(), update() and buildTree()

* Implemented Splay Tree Data Structure

* Update tests/DataStructures/SplayTreeTest.php

Co-authored-by: Brandon Johnson <[email protected]>

* Implemented Trie Data Structure. Added case-insensitive feature to the Trie implementation. Added corresponding unit testing.

---------

Co-authored-by: Brandon Johnson <[email protected]>
Co-authored-by: Ramy-Badr-Ahmed <[email protected]>
  • Loading branch information
3 people authored Oct 15, 2024
1 parent ea4d3b0 commit 3360474
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 4 deletions.
4 changes: 3 additions & 1 deletion DataStructures/Trie/Trie.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<?php

/*
* Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #162
* Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request #162 and #172
* https://github.com/TheAlgorithms/PHP/pull/162
* https://github.com/TheAlgorithms/PHP/pull/172
*
* Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file.
* Thank you!
Expand Down Expand Up @@ -61,6 +62,7 @@ public function search(string $word): bool
*/
public function startsWith(string $prefix): array
{
$prefix = strtolower($prefix); // Normalize the prefix to lowercase
$node = $this->root;
for ($i = 0; $i < strlen($prefix); $i++) {
$char = $prefix[$i];
Expand Down
14 changes: 13 additions & 1 deletion DataStructures/Trie/TrieNode.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<?php

/*
* Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #162
* Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request #162 and #172
* https://github.com/TheAlgorithms/PHP/pull/162
* https://github.com/TheAlgorithms/PHP/pull/172
*
* Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file.
* Thank you!
Expand All @@ -27,6 +28,7 @@ public function __construct()
*/
public function addChild(string $char): TrieNode
{
$char = $this->normalizeChar($char);
if (!isset($this->children[$char])) {
$this->children[$char] = new TrieNode();
}
Expand All @@ -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]);
}

Expand All @@ -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);
}
}
161 changes: 159 additions & 2 deletions tests/DataStructures/TrieTest.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<?php

/*
* Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request: #162
* Created by: Ramy-Badr-Ahmed (https://github.com/Ramy-Badr-Ahmed) in Pull Request #162 and #172
* https://github.com/TheAlgorithms/PHP/pull/162
* https://github.com/TheAlgorithms/PHP/pull/172
*
* Please mention me (@Ramy-Badr-Ahmed) in any issue or pull request addressing bugs/corrections to this file.
* Thank you!
Expand All @@ -14,6 +15,7 @@
require_once __DIR__ . '/../../DataStructures/Trie/TrieNode.php';

use DataStructures\Trie\Trie;
use DataStructures\Trie\TrieNode;
use PHPUnit\Framework\TestCase;

class TrieTest extends TestCase
Expand All @@ -25,6 +27,9 @@ protected function setUp(): void
$this->trie = new Trie();
}

/**
* Test insertion and search functionality of the Trie.
*/
public function testInsertAndSearch()
{
$this->trie->insert('the');
Expand All @@ -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('[email protected]');
$this->assertTrue($this->trie->search('hello123'), 'Expected "hello123" to be found in the Trie.');
$this->assertTrue(
$this->trie->search('[email protected]'),
'Expected "[email protected]" 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');
Expand All @@ -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');
Expand All @@ -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');
Expand All @@ -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');
Expand All @@ -117,19 +231,28 @@ 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('');
$this->trie->delete('');
$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');
Expand All @@ -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".');
}
}

0 comments on commit 3360474

Please sign in to comment.