From 427c5ca0b09b55614c6cc0fd8f650357d156014f Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sat, 4 Jan 2025 20:45:36 +0100 Subject: [PATCH 01/16] update typing and add PHPDocs --- src/helper/Node.php | 42 ++++++++++++++++++++++++++++++++++++------ src/helper/Tree.php | 17 ++++++++++++++--- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/helper/Node.php b/src/helper/Node.php index e26255f..cdbedd3 100644 --- a/src/helper/Node.php +++ b/src/helper/Node.php @@ -7,9 +7,13 @@ class Node private Node|null $parent; private Node|null $right; private Node|null $left; - private Int $value; + private float|int $value; - public function __construct($value, Node $node = null) + /** + * @param float|int $value + * @param Node|null $node + */ + public function __construct(float|int $value, Node $node = null) { $this->parent = $node; $this->value = $value; @@ -17,34 +21,58 @@ public function __construct($value, Node $node = null) $this->right = null; } + /** + * @return Node|null the parent of the node + */ public function parent(): Node|null { return $this->parent; } - public function value(): Int + /** + * @return float|int + */ + public function value(): float|int { return $this->value; } + /** + * @return Node|null the left child + */ public function left(): Node|null { return $this->left; } + /** + * @return Node|null the right child + */ public function right(): Node|null { return $this->right; } - public function setLeft($value): Node + /** + * set the left child as as a new Node with provided value + * + * @param float|int $value + * @return Node + */ + public function setLeft(float|int $value): Node { $newNode = new Node($value, $this); return $this->left = $newNode; } - public function setRight($value): Node + /** + * set the right child as as a new Node with provided value + * + * @param float|int $value + * @return Node + */ + public function setRight(float|int $value): Node { $newNode = new Node($value, $this); @@ -52,6 +80,8 @@ public function setRight($value): Node } /** + * travel the tree from the current node and return array representation + * * @return array */ public function flatten(): array @@ -61,7 +91,7 @@ public function flatten(): array if ($this->left() != null) { $left = $this->left()->flatten(); } - if ($this->right != null) { + if ($this->right() != null) { $right = $this->right()->flatten(); } diff --git a/src/helper/Tree.php b/src/helper/Tree.php index 35ea570..c873de0 100644 --- a/src/helper/Tree.php +++ b/src/helper/Tree.php @@ -6,17 +6,28 @@ class Tree { private ?Node $root; - public function __construct($value) + /** + * @param float|int $value + */ + public function __construct(float|int $value) { $this->root = new Node($value); } - public function root(): Node + /** + * @return Node|null + */ + public function root(): ?Node { return $this->root; } - public function put($value, Node $node = null): void + /** + * @param float|int $value + * @param Node|null $node + * @return void + */ + public function put(float|int $value, Node $node = null): void { if ($node == null) { $this->put($value, $this->root); From f0fdb15d2d951a99a2d1a96ba4ebcfaadf4128a2 Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sat, 4 Jan 2025 20:46:24 +0100 Subject: [PATCH 02/16] remove usage of getter in class --- src/helper/Node.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helper/Node.php b/src/helper/Node.php index cdbedd3..8eeb356 100644 --- a/src/helper/Node.php +++ b/src/helper/Node.php @@ -88,11 +88,11 @@ public function flatten(): array { $left = []; $right = []; - if ($this->left() != null) { - $left = $this->left()->flatten(); + if ($this->left != null) { + $left = $this->left->flatten(); } - if ($this->right() != null) { - $right = $this->right()->flatten(); + if ($this->right != null) { + $right = $this->right->flatten(); } return array_merge($left, [$this->value], $right); From 20310f26394077f8fea0ab4cb0f0f92323395f2f Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sat, 4 Jan 2025 20:55:45 +0100 Subject: [PATCH 03/16] add search traversal trough tree --- src/helper/Tree.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/helper/Tree.php b/src/helper/Tree.php index c873de0..f4e0d5e 100644 --- a/src/helper/Tree.php +++ b/src/helper/Tree.php @@ -48,4 +48,25 @@ public function put(float|int $value, Node $node = null): void } } } + + /** + * search for node with provided value and remove it from tree + * + * @param float|int $value to search and remove + * @return float|int|null the value found or null on not existing + */ + public function pull(float|int $value): float|int|null + { + $pointer = $this->root; + do { + if ($pointer->value() < $value) { + $pointer = $pointer->right(); + } elseif ($value < $pointer->value() ) { + $pointer = $pointer->left(); + } + } while ($pointer && $pointer->value() != $value); + if (!$pointer) { + return null; + } + } } From a16ffe7b5f31fff12cd06ca0ebdc80a87e773dcc Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sat, 4 Jan 2025 20:57:01 +0100 Subject: [PATCH 04/16] change do while to while loop --- src/helper/Tree.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/helper/Tree.php b/src/helper/Tree.php index f4e0d5e..5233a83 100644 --- a/src/helper/Tree.php +++ b/src/helper/Tree.php @@ -58,13 +58,13 @@ public function put(float|int $value, Node $node = null): void public function pull(float|int $value): float|int|null { $pointer = $this->root; - do { + while ($pointer && $pointer->value() != $value) { if ($pointer->value() < $value) { $pointer = $pointer->right(); } elseif ($value < $pointer->value() ) { $pointer = $pointer->left(); } - } while ($pointer && $pointer->value() != $value); + } if (!$pointer) { return null; } From a1d92d991efa7af0d91f821047311c9756de872b Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sat, 4 Jan 2025 20:57:06 +0100 Subject: [PATCH 05/16] formatting --- src/helper/Tree.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper/Tree.php b/src/helper/Tree.php index 5233a83..0f5b3b9 100644 --- a/src/helper/Tree.php +++ b/src/helper/Tree.php @@ -61,7 +61,7 @@ public function pull(float|int $value): float|int|null while ($pointer && $pointer->value() != $value) { if ($pointer->value() < $value) { $pointer = $pointer->right(); - } elseif ($value < $pointer->value() ) { + } elseif ($value < $pointer->value()) { $pointer = $pointer->left(); } } From b09ac5ee88f98f04f9b996504cbb9f93611175c0 Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sun, 5 Jan 2025 13:18:05 +0100 Subject: [PATCH 06/16] update setter to accept Node --- src/helper/Node.php | 20 ++++++++------------ src/helper/Tree.php | 6 ++++-- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/helper/Node.php b/src/helper/Node.php index 8eeb356..0bf7f0a 100644 --- a/src/helper/Node.php +++ b/src/helper/Node.php @@ -54,29 +54,25 @@ public function right(): Node|null } /** - * set the left child as as a new Node with provided value + * set the left child to provided Node * - * @param float|int $value + * @param Node $node * @return Node */ - public function setLeft(float|int $value): Node + public function setLeft(Node $node): Node { - $newNode = new Node($value, $this); - - return $this->left = $newNode; + return $this->left = $node; } /** - * set the right child as as a new Node with provided value + * set the right child to provided Node * - * @param float|int $value + * @param Node $node * @return Node */ - public function setRight(float|int $value): Node + public function setRight(Node $node): Node { - $newNode = new Node($value, $this); - - return $this->right = $newNode; + return $this->right = $node; } /** diff --git a/src/helper/Tree.php b/src/helper/Tree.php index 0f5b3b9..4058696 100644 --- a/src/helper/Tree.php +++ b/src/helper/Tree.php @@ -36,13 +36,15 @@ public function put(float|int $value, Node $node = null): void } if ($node->value() < $value) { if ($node->right() == null) { - $node->setRight($value); + $newNode = new Node($value, $node); + $node->setRight($newNode); } else { $this->put($value, $node->right()); } } else { if ($node->left() == null) { - $node->setLeft($value); + $newNode = new Node($value, $node); + $node->setLeft($newNode); } else { $this->put($value, $node->left()); } From 3e96a12260da239ae834289014adbdf06d84bb33 Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sun, 5 Jan 2025 13:30:57 +0100 Subject: [PATCH 07/16] add update of parent of deleted node --- src/helper/Tree.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/helper/Tree.php b/src/helper/Tree.php index 4058696..dd4f95a 100644 --- a/src/helper/Tree.php +++ b/src/helper/Tree.php @@ -70,5 +70,15 @@ public function pull(float|int $value): float|int|null if (!$pointer) { return null; } + $replacement = $pointer->left() ?? $pointer->right(); + if ($pointer->parent()) { + if ($pointer->parent()->left() === $pointer) { + $pointer = $pointer->parent()->setLeft($replacement); + } else { + $pointer = $pointer->parent()->setRight($replacement); + } + } else { + $this->root = $replacement; + } } } From 6ef7c38b1f23d1d8a33f9c5778da08e7ea408c69 Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sun, 5 Jan 2025 13:33:08 +0100 Subject: [PATCH 08/16] allow null values in setter --- src/helper/Node.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helper/Node.php b/src/helper/Node.php index 0bf7f0a..841efec 100644 --- a/src/helper/Node.php +++ b/src/helper/Node.php @@ -56,10 +56,10 @@ public function right(): Node|null /** * set the left child to provided Node * - * @param Node $node + * @param ?Node $node * @return Node */ - public function setLeft(Node $node): Node + public function setLeft(?Node $node): Node { return $this->left = $node; } @@ -67,10 +67,10 @@ public function setLeft(Node $node): Node /** * set the right child to provided Node * - * @param Node $node + * @param ?Node $node * @return Node */ - public function setRight(Node $node): Node + public function setRight(?Node $node): Node { return $this->right = $node; } From b0e74c03805d349bab154e95ef179196a12063a0 Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sun, 5 Jan 2025 19:51:17 +0100 Subject: [PATCH 09/16] add setter for parent --- src/helper/Node.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/helper/Node.php b/src/helper/Node.php index 841efec..f35c64e 100644 --- a/src/helper/Node.php +++ b/src/helper/Node.php @@ -53,6 +53,17 @@ public function right(): Node|null return $this->right; } + /** + * set the parent to provided Node + * + * @param ?Node $node + * @return Node + */ + public function setParent(?Node $node): Node + { + return $this->parent = $node; + } + /** * set the left child to provided Node * From b32376733176131b8e524e07a3c2bfa0bb20ebda Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sun, 5 Jan 2025 20:02:06 +0100 Subject: [PATCH 10/16] drop initial approach of handling leaf nodes --- src/helper/Tree.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/helper/Tree.php b/src/helper/Tree.php index dd4f95a..4058696 100644 --- a/src/helper/Tree.php +++ b/src/helper/Tree.php @@ -70,15 +70,5 @@ public function pull(float|int $value): float|int|null if (!$pointer) { return null; } - $replacement = $pointer->left() ?? $pointer->right(); - if ($pointer->parent()) { - if ($pointer->parent()->left() === $pointer) { - $pointer = $pointer->parent()->setLeft($replacement); - } else { - $pointer = $pointer->parent()->setRight($replacement); - } - } else { - $this->root = $replacement; - } } } From 44b41c7ce995acf0657229453014fdbfedb1158c Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sun, 5 Jan 2025 20:07:07 +0100 Subject: [PATCH 11/16] add guard case to remove potential root node --- src/helper/Tree.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/helper/Tree.php b/src/helper/Tree.php index 4058696..cc026b6 100644 --- a/src/helper/Tree.php +++ b/src/helper/Tree.php @@ -70,5 +70,9 @@ public function pull(float|int $value): float|int|null if (!$pointer) { return null; } + if (!$pointer->parent()) { + $this->root = null; + return $value; + } } } From 6f076c0a61d64ddaa7eb5b75d63b22d65ffc2499 Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sun, 5 Jan 2025 20:08:44 +0100 Subject: [PATCH 12/16] add guard case for leaf nodes --- src/helper/Tree.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/helper/Tree.php b/src/helper/Tree.php index cc026b6..6e0f190 100644 --- a/src/helper/Tree.php +++ b/src/helper/Tree.php @@ -74,5 +74,12 @@ public function pull(float|int $value): float|int|null $this->root = null; return $value; } + if(!$pointer->left() && !$pointer->right()) { + if ($pointer->parent()->left() === $pointer) { + $pointer->parent()->setLeft(null); + } else { + $pointer->parent()->setRight(null); + } + } } } From 8b75a9d070f47778b60a985c4afa4e30e37be426 Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sun, 5 Jan 2025 20:09:26 +0100 Subject: [PATCH 13/16] formatting and terminating of method --- src/helper/Tree.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/helper/Tree.php b/src/helper/Tree.php index 6e0f190..3c82596 100644 --- a/src/helper/Tree.php +++ b/src/helper/Tree.php @@ -74,12 +74,13 @@ public function pull(float|int $value): float|int|null $this->root = null; return $value; } - if(!$pointer->left() && !$pointer->right()) { + if (!$pointer->left() && !$pointer->right()) { if ($pointer->parent()->left() === $pointer) { $pointer->parent()->setLeft(null); } else { $pointer->parent()->setRight(null); } + return $value; } } } From e26fdd6d097eaa97ebe32ea6fa0f6945ae2a27cc Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sun, 5 Jan 2025 20:16:47 +0100 Subject: [PATCH 14/16] add guard case for only left child --- src/helper/Tree.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/helper/Tree.php b/src/helper/Tree.php index 3c82596..32648b5 100644 --- a/src/helper/Tree.php +++ b/src/helper/Tree.php @@ -82,5 +82,30 @@ public function pull(float|int $value): float|int|null } return $value; } + if(!$pointer->right()) { + $pointer->left()->setParent($pointer->parent()); + if ($pointer->parent()->left() === $pointer) { + $pointer->parent()->setLeft($pointer->left()); + } else { + $pointer->parent()->setRight($pointer->left()); + } + return $value; + } + + + + + + + if ($pointer->parent()->left() === $pointer) { + $pointer->parent()->setLeft($inorderSuccessor); + } else { + $pointer->parent()->setRight($inorderSuccessor); + } $pointer->left()->setParent($pointer->parent()); + if ($pointer->parent()->left() === $pointer) { + $pointer = $pointer->parent()->setLeft($pointer->left()); + } else { + $pointer = $pointer->parent()->setRight($pointer->left()); + } } } From 3cf59b0ab92f4c10e09328aaabea743a7096eb72 Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sun, 5 Jan 2025 20:25:39 +0100 Subject: [PATCH 15/16] remove initial approach for two children case --- src/helper/Tree.php | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/helper/Tree.php b/src/helper/Tree.php index 32648b5..50bbadc 100644 --- a/src/helper/Tree.php +++ b/src/helper/Tree.php @@ -91,21 +91,5 @@ public function pull(float|int $value): float|int|null } return $value; } - - - - - - - if ($pointer->parent()->left() === $pointer) { - $pointer->parent()->setLeft($inorderSuccessor); - } else { - $pointer->parent()->setRight($inorderSuccessor); - } $pointer->left()->setParent($pointer->parent()); - if ($pointer->parent()->left() === $pointer) { - $pointer = $pointer->parent()->setLeft($pointer->left()); - } else { - $pointer = $pointer->parent()->setRight($pointer->left()); - } } } From dc353ada762a2ef2459da011e4a9c32047c2116d Mon Sep 17 00:00:00 2001 From: dimitrijjedich Date: Sun, 5 Jan 2025 20:26:37 +0100 Subject: [PATCH 16/16] add two children case by replacing node with in order successor --- src/helper/Tree.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/helper/Tree.php b/src/helper/Tree.php index 50bbadc..e167c44 100644 --- a/src/helper/Tree.php +++ b/src/helper/Tree.php @@ -91,5 +91,23 @@ public function pull(float|int $value): float|int|null } return $value; } + $inorderSuccessor = $pointer->right(); + while ($inorderSuccessor->left()) { + $inorderSuccessor = $inorderSuccessor->left(); + } + if ($inorderSuccessor->parent()->left() === $inorderSuccessor) { + $inorderSuccessor->parent()->setLeft($inorderSuccessor->right()); + } else { + $inorderSuccessor->parent()->setRight($inorderSuccessor->right()); + } + if ($pointer->parent()->left() === $pointer) { + $pointer->parent()->setLeft($inorderSuccessor); + } else { + $pointer->parent()->setRight($inorderSuccessor); + } + $inorderSuccessor->setRight($pointer->right()); + $inorderSuccessor->setLeft($pointer->left()); + $pointer->left()->setParent($inorderSuccessor); + return $value; } }