Skip to content

Commit

Permalink
Merge pull request #13 from KaririCode-Framework/develop
Browse files Browse the repository at this point in the history
refactor(Tree): Move TreeMapNode to Tree directory and add TreeNode w…
  • Loading branch information
walmir-silva authored Sep 27, 2024
2 parents 05bf44a + 8cc515e commit 9a49838
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 6 deletions.
4 changes: 2 additions & 2 deletions src/Map/TreeMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use KaririCode\Contract\DataStructure\Behavioral\IterableCollection;
use KaririCode\Contract\DataStructure\Map;
use KaririCode\DataStructure\TreeMapNode;
use KaririCode\DataStructure\Tree\TreeMapNode;

/**
* TreeMap implementation.
Expand Down Expand Up @@ -206,7 +206,7 @@ private function balanceAfterInsertion(TreeMapNode $node): void
}
}
}
$this->root->setBlack();
$this->root?->setBlack();
}

private function rotateLeft(TreeMapNode $node): void
Expand Down
2 changes: 1 addition & 1 deletion src/TreeMapNode.php → src/Tree/TreeMapNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace KaririCode\DataStructure;
namespace KaririCode\DataStructure\Tree;

/**
* TreeMapNode class.
Expand Down
86 changes: 86 additions & 0 deletions src/Tree/TreeNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

declare(strict_types=1);

namespace KaririCode\DataStructure\Tree;

/**
* TreeNode class.
*
* This class represents a generic node in a binary tree, which can be used for various tree structures.
* Each node contains a key, a value, and references to its left and right child nodes, as well as an optional parent node.
*
* @category Data Structures
*
* @author Walmir Silva
* @license MIT
*
* @see https://kariricode.org/
*/
class TreeNode
{
public function __construct(
public mixed $key,
public mixed $value,
public ?TreeNode $left = null,
public ?TreeNode $right = null,
public ?TreeNode $parent = null
) {
}

/**
* Sets the left child of this node and updates the parent reference of the child node.
*/
public function setLeft(?TreeNode $node): void
{
$this->left = $node;
if (null !== $node) {
$node->parent = $this;
}
}

/**
* Sets the right child of this node and updates the parent reference of the child node.
*/
public function setRight(?TreeNode $node): void
{
$this->right = $node;
if (null !== $node) {
$node->parent = $this;
}
}

/**
* Removes this node from its parent node, detaching it from the tree.
*/
public function removeFromParent(): void
{
if (null !== $this->parent) {
if ($this === $this->parent->left) {
$this->parent->left = null;
} else {
$this->parent->right = null;
}
$this->parent = null;
}
}

/**
* Replaces this node with the specified replacement node.
*
* @param TreeNode $replacement the node that will replace the current node
*
* @throws \RuntimeException if trying to replace the root node without a parent
*/
public function replaceWith(TreeNode $replacement): void
{
if (null === $this->parent) {
throw new \RuntimeException('Cannot replace root node');
}
if ($this === $this->parent->left) {
$this->parent->setLeft($replacement);
} else {
$this->parent->setRight($replacement);
}
}
}
Empty file removed src/TreeNode.php
Empty file.
2 changes: 1 addition & 1 deletion tests/Map/TreeMapTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace KaririCode\DataStructure\Tests\Map;

use KaririCode\DataStructure\Map\TreeMap;
use KaririCode\DataStructure\TreeMapNode;
use KaririCode\DataStructure\Tree\TreeMapNode;
use PHPUnit\Framework\TestCase;

final class TreeMapTest extends TestCase
Expand Down
4 changes: 2 additions & 2 deletions tests/TreeMapNodeTest.php → tests/Tree/TreeMapNodeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

declare(strict_types=1);

namespace KaririCode\DataStructure\Tests\Map;
namespace KaririCode\DataStructure\Tests\Tree;

use KaririCode\DataStructure\TreeMapNode;
use KaririCode\DataStructure\Tree\TreeMapNode;
use PHPUnit\Framework\TestCase;

final class TreeMapNodeTest extends TestCase
Expand Down
118 changes: 118 additions & 0 deletions tests/Tree/TreeNodeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

declare(strict_types=1);

use KaririCode\DataStructure\Tree\TreeNode;
use PHPUnit\Framework\TestCase;

final class TreeNodeTest extends TestCase
{
public function testCreateNode(): void
{
$node = new TreeNode(1, 'valor1');

$this->assertSame(1, $node->key);
$this->assertSame('valor1', $node->value);
$this->assertNull($node->left);
$this->assertNull($node->right);
$this->assertNull($node->parent);
}

public function testSetLeftChild(): void
{
$parent = new TreeNode(1, 'parent');
$child = new TreeNode(2, 'child');

$parent->setLeft($child);

$this->assertSame($child, $parent->left);
$this->assertSame($parent, $child->parent);
}

public function testSetRightChild(): void
{
$parent = new TreeNode(1, 'parent');
$child = new TreeNode(2, 'child');

$parent->setRight($child);

$this->assertSame($child, $parent->right);
$this->assertSame($parent, $child->parent);
}

public function testRemoveFromParent(): void
{
$parent = new TreeNode(1, 'parent');
$child = new TreeNode(2, 'child');

$parent->setLeft($child);
$child->removeFromParent();

$this->assertNull($parent->left);
$this->assertNull($child->parent);
}

public function testReplaceWith(): void
{
$parent = new TreeNode(1, 'parent');
$child = new TreeNode(2, 'child');
$replacement = new TreeNode(3, 'replacement');

$parent->setLeft($child);
$child->replaceWith($replacement);

$this->assertSame($replacement, $parent->left);
$this->assertSame($parent, $replacement->parent);
}

public function testSetRightAndLeftTogether(): void
{
$parent = new TreeNode(1, 'parent');
$leftChild = new TreeNode(2, 'left');
$rightChild = new TreeNode(3, 'right');

$parent->setLeft($leftChild);
$parent->setRight($rightChild);

$this->assertSame($leftChild, $parent->left);
$this->assertSame($rightChild, $parent->right);
$this->assertSame($parent, $leftChild->parent);
$this->assertSame($parent, $rightChild->parent);
}

public function testReplaceWithThrowsExceptionWhenNodeIsRoot(): void
{
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Cannot replace root node');

$root = new TreeNode(1, 'root');
$replacement = new TreeNode(2, 'replacement');

$root->replaceWith($replacement);
}

public function testRemoveFromParentRightChild(): void
{
$parent = new TreeNode(1, 'parent');
$child = new TreeNode(2, 'child');

$parent->setRight($child);
$child->removeFromParent();

$this->assertNull($parent->right);
$this->assertNull($child->parent);
}

public function testReplaceWithRightChild(): void
{
$parent = new TreeNode(1, 'parent');
$child = new TreeNode(2, 'child');
$replacement = new TreeNode(3, 'replacement');

$parent->setRight($child);
$child->replaceWith($replacement);

$this->assertSame($replacement, $parent->right);
$this->assertSame($parent, $replacement->parent);
}
}

0 comments on commit 9a49838

Please sign in to comment.