mirror of
https://github.com/TheAlgorithms/PHP.git
synced 2025-07-26 19:30:11 +02:00
Implemented Disjoint Set (Union-Find) Data Structure (#160)
* Added Disjoint Sets Data structure * Moved DisjointSetTest.php to tests/DataStructures * Update DataStructures/DisjointSets/DisjointSet.php Co-authored-by: Brandon Johnson <bbj1979@gmail.com> * Update DataStructures/DisjointSets/DisjointSetNode.php Co-authored-by: Brandon Johnson <bbj1979@gmail.com> * Update DataStructures/DisjointSets/DisjointSetNode.php Co-authored-by: Brandon Johnson <bbj1979@gmail.com> * Update tests/DataStructures/DisjointSetTest.php Co-authored-by: Brandon Johnson <bbj1979@gmail.com> * Update tests/DataStructures/DisjointSetTest.php Co-authored-by: Brandon Johnson <bbj1979@gmail.com> * Update tests/DataStructures/DisjointSetTest.php Co-authored-by: Brandon Johnson <bbj1979@gmail.com> * 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 --------- Co-authored-by: Brandon Johnson <bbj1979@gmail.com> Co-authored-by: Ramy-Badr-Ahmed <Ramy-Badr-Ahmed@users.noreply.github.com>
This commit is contained in:
@@ -17,6 +17,9 @@
|
|||||||
* [Speedconversion](./Conversions/SpeedConversion.php)
|
* [Speedconversion](./Conversions/SpeedConversion.php)
|
||||||
|
|
||||||
## Datastructures
|
## Datastructures
|
||||||
|
* Disjointsets
|
||||||
|
* [Disjointset](./DataStructures/DisjointSets/DisjointSet.php)
|
||||||
|
* [Disjointsetnode](./DataStructures/DisjointSets/DisjointSetNode.php)
|
||||||
* [Doublylinkedlist](./DataStructures/DoublyLinkedList.php)
|
* [Doublylinkedlist](./DataStructures/DoublyLinkedList.php)
|
||||||
* [Node](./DataStructures/Node.php)
|
* [Node](./DataStructures/Node.php)
|
||||||
* [Queue](./DataStructures/Queue.php)
|
* [Queue](./DataStructures/Queue.php)
|
||||||
@@ -111,6 +114,7 @@
|
|||||||
* Conversions
|
* Conversions
|
||||||
* [Conversionstest](./tests/Conversions/ConversionsTest.php)
|
* [Conversionstest](./tests/Conversions/ConversionsTest.php)
|
||||||
* Datastructures
|
* Datastructures
|
||||||
|
* [Disjointsettest](./tests/DataStructures/DisjointSetTest.php)
|
||||||
* [Doublylinkedlisttest](./tests/DataStructures/DoublyLinkedListTest.php)
|
* [Doublylinkedlisttest](./tests/DataStructures/DoublyLinkedListTest.php)
|
||||||
* [Queuetest](./tests/DataStructures/QueueTest.php)
|
* [Queuetest](./tests/DataStructures/QueueTest.php)
|
||||||
* [Singlylinkedlisttest](./tests/DataStructures/SinglyLinkedListTest.php)
|
* [Singlylinkedlisttest](./tests/DataStructures/SinglyLinkedListTest.php)
|
||||||
|
41
DataStructures/DisjointSets/DisjointSet.php
Normal file
41
DataStructures/DisjointSets/DisjointSet.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DataStructures\DisjointSets;
|
||||||
|
|
||||||
|
class DisjointSet
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Finds the representative of the set that contains the node.
|
||||||
|
*/
|
||||||
|
public function findSet(DisjointSetNode $node): DisjointSetNode
|
||||||
|
{
|
||||||
|
if ($node !== $node->parent) {
|
||||||
|
// Path compression: make the parent point directly to the root
|
||||||
|
$node->parent = $this->findSet($node->parent);
|
||||||
|
}
|
||||||
|
return $node->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unites the sets that contain x and y.
|
||||||
|
*/
|
||||||
|
public function unionSet(DisjointSetNode $nodeX, DisjointSetNode $nodeY): void
|
||||||
|
{
|
||||||
|
$rootX = $this->findSet($nodeX);
|
||||||
|
$rootY = $this->findSet($nodeY);
|
||||||
|
|
||||||
|
if ($rootX === $rootY) {
|
||||||
|
return; // They are already in the same set
|
||||||
|
}
|
||||||
|
|
||||||
|
// Union by rank: attach the smaller tree under the larger tree
|
||||||
|
if ($rootX->rank > $rootY->rank) {
|
||||||
|
$rootY->parent = $rootX;
|
||||||
|
} else {
|
||||||
|
$rootX->parent = $rootY;
|
||||||
|
if ($rootX->rank === $rootY->rank) {
|
||||||
|
$rootY->rank += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
DataStructures/DisjointSets/DisjointSetNode.php
Normal file
21
DataStructures/DisjointSets/DisjointSetNode.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DataStructures\DisjointSets;
|
||||||
|
|
||||||
|
class DisjointSetNode
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int|string|float|null
|
||||||
|
*/
|
||||||
|
// PHP7.4: Defined with annotations
|
||||||
|
public $data; # replace with type hint "mixed" as of PHP 8.0^.
|
||||||
|
public int $rank;
|
||||||
|
public DisjointSetNode $parent;
|
||||||
|
|
||||||
|
public function __construct($data = null)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
$this->rank = 0;
|
||||||
|
$this->parent = $this; // Initialize parent to itself
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name" : "thealgorithms/php",
|
"name": "thealgorithms/php",
|
||||||
"description": "All Algorithms implemented in PHP",
|
"description": "All Algorithms implemented in PHP",
|
||||||
"config": {
|
"config": {
|
||||||
"platform": {
|
"platform": {
|
||||||
@@ -19,3 +19,4 @@
|
|||||||
"test": "vendor/bin/phpunit tests"
|
"test": "vendor/bin/phpunit tests"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
87
tests/DataStructures/DisjointSetTest.php
Normal file
87
tests/DataStructures/DisjointSetTest.php
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DataStructures;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../DataStructures/DisjointSets/DisjointSet.php';
|
||||||
|
require_once __DIR__ . '/../../DataStructures/DisjointSets/DisjointSetNode.php';
|
||||||
|
|
||||||
|
use DataStructures\DisjointSets\DisjointSet;
|
||||||
|
use DataStructures\DisjointSets\DisjointSetNode;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DisjointSetTest extends TestCase
|
||||||
|
{
|
||||||
|
private DisjointSet $ds;
|
||||||
|
private array $nodes;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$this->ds = new DisjointSet();
|
||||||
|
$this->nodes = [];
|
||||||
|
|
||||||
|
// Create 20 nodes
|
||||||
|
for ($i = 0; $i < 20; $i++) {
|
||||||
|
$this->nodes[$i] = new DisjointSetNode($i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform union operations to form several disjoint sets
|
||||||
|
$this->ds->unionSet($this->nodes[0], $this->nodes[1]);
|
||||||
|
$this->ds->unionSet($this->nodes[1], $this->nodes[2]);
|
||||||
|
|
||||||
|
$this->ds->unionSet($this->nodes[3], $this->nodes[4]);
|
||||||
|
$this->ds->unionSet($this->nodes[4], $this->nodes[5]);
|
||||||
|
|
||||||
|
$this->ds->unionSet($this->nodes[6], $this->nodes[7]);
|
||||||
|
$this->ds->unionSet($this->nodes[7], $this->nodes[8]);
|
||||||
|
|
||||||
|
$this->ds->unionSet($this->nodes[9], $this->nodes[10]);
|
||||||
|
$this->ds->unionSet($this->nodes[10], $this->nodes[11]);
|
||||||
|
|
||||||
|
$this->ds->unionSet($this->nodes[12], $this->nodes[13]);
|
||||||
|
$this->ds->unionSet($this->nodes[13], $this->nodes[14]);
|
||||||
|
|
||||||
|
$this->ds->unionSet($this->nodes[15], $this->nodes[16]);
|
||||||
|
$this->ds->unionSet($this->nodes[16], $this->nodes[17]);
|
||||||
|
|
||||||
|
$this->ds->unionSet($this->nodes[18], $this->nodes[19]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFindSet(): void
|
||||||
|
{
|
||||||
|
// Nodes in the same sets should have the same root
|
||||||
|
for ($i = 0; $i < 6; $i++) {
|
||||||
|
for ($j = 0; $j < 6; $j++) {
|
||||||
|
$setI = $this->ds->findSet($this->nodes[$i]);
|
||||||
|
$setJ = $this->ds->findSet($this->nodes[$j]);
|
||||||
|
|
||||||
|
if ($this->inSameSet($i, $j)) {
|
||||||
|
$this->assertSame($setI, $setJ, "Nodes $i and $j should be in the same set");
|
||||||
|
} else {
|
||||||
|
$this->assertNotSame($setI, $setJ, "Nodes $i and $j should be in different sets");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function inSameSet(int $i, int $j): bool
|
||||||
|
{
|
||||||
|
// Define which nodes should be in the same set based on union operations
|
||||||
|
$sets = [
|
||||||
|
[0, 1, 2], // Set A
|
||||||
|
[3, 4, 5], // Set B
|
||||||
|
[6, 7, 8], // Set C
|
||||||
|
[9, 10, 11], // Set D
|
||||||
|
[12, 13, 14], // Set E
|
||||||
|
[15, 16, 17], // Set F
|
||||||
|
[18, 19] // Set G
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($sets as $set) {
|
||||||
|
if (in_array($i, $set) && in_array($j, $set)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user