From 5abba4ea7734ad7c1fb405f525e6f383862e649f Mon Sep 17 00:00:00 2001 From: Mahmoud Ashraf <182176867+SNO7E-G@users.noreply.github.com> Date: Wed, 25 Mar 2026 10:49:17 +0500 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Modernize=20codebase=20to=20PHP=208?= =?UTF-8?q?.2+:=20enforce=20strict=20types,=20PSR-12,=20and=20matrix=20CI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 5 +- .github/workflows/code-style.yml | 4 +- CONTRIBUTING.md | 37 +++++---- Ciphers/AtbashCipher.php | 8 +- Ciphers/CaesarCipher.php | 3 + Ciphers/MonoAlphabeticCipher.php | 20 ++--- Ciphers/MorseCode.php | 33 +++++--- Ciphers/RailfenceCipher.php | 20 +++-- Ciphers/VignereCipher.php | 4 + Ciphers/XORCipher.php | 10 ++- Conversions/BinaryToDecimal.php | 8 +- Conversions/DecimalToBinary.php | 5 +- Conversions/HexadecimalToDecimal.php | 27 ++++--- Conversions/OctalToDecimal.php | 14 ++-- Conversions/SpeedConversion.php | 9 +-- Conversions/TemperatureConversions.php | 20 ++--- DataStructures/AVLTree/AVLTree.php | 64 +++++++-------- DataStructures/AVLTree/AVLTreeNode.php | 31 +++----- DataStructures/AVLTree/TreeTraversal.php | 15 ++-- DataStructures/BinarySearchTree/BSTNode.php | 33 ++++---- DataStructures/BinarySearchTree/BSTree.php | 57 +++++++------ .../BinarySearchTree/BinaryTreeTraversal.php | 48 ++++++----- .../DuplicateKeyException.php | 2 + .../CompareBinaryTree/BinaryTreeNode.php | 11 +-- .../CompareBinaryTree/CompareBinaryTree.php | 10 +-- DataStructures/DisjointSets/DisjointSet.php | 3 + .../DisjointSets/DisjointSetNode.php | 18 ++--- DataStructures/DoublyLinkedList.php | 62 +++++++-------- .../InvertBinaryTree/BinaryTree.php | 10 ++- .../InvertBinaryTree/InvertBinaryTree.php | 5 +- DataStructures/Node.php | 7 +- DataStructures/Queue.php | 19 ++--- .../ReverseLinkedList/LinkedListItem.php | 10 ++- .../ReverseLinkedList/ReverseLinkedList.php | 5 +- DataStructures/SegmentTree/SegmentTree.php | 74 +++++++++-------- .../SegmentTree/SegmentTreeNode.php | 20 ++--- DataStructures/SinglyLinkedList.php | 10 +-- DataStructures/SplayTree/SplayTree.php | 79 +++++++++++-------- DataStructures/SplayTree/SplayTreeNode.php | 31 +++----- .../SplayTree/SplayTreeRotations.php | 15 ++-- DataStructures/Stack.php | 17 ++-- DataStructures/Trie/Trie.php | 14 +++- DataStructures/Trie/TrieNode.php | 12 ++- Graphs/BellmanFord.php | 15 +++- Graphs/BreadthFirstSearch.php | 12 ++- Graphs/DepthFirstSearch.php | 9 ++- Graphs/Dijkstras.php | 9 ++- Graphs/GraphEdge.php | 4 + Maths/AbsoluteMax.php | 7 +- Maths/AbsoluteMin.php | 7 +- Maths/ArmstrongNumber.php | 13 ++- Maths/BaseX.php | 6 +- Maths/CheckEven.php | 2 + Maths/CheckOdd.php | 2 + Maths/CheckPalindrome.php | 12 +-- Maths/CheckPrime.php | 7 +- Maths/EratosthenesSieve.php | 5 ++ Maths/Factorial.php | 2 + Maths/FastExponentiation.php | 5 +- Maths/FastInverseSquareRoot.php | 4 +- Maths/Fibonacci.php | 40 +++++----- Maths/Fibonacci2.php | 10 ++- Maths/GreatestCommonDivisor.php | 6 +- Maths/Mean.php | 6 +- Maths/Median.php | 6 +- Maths/Mode.php | 6 +- Maths/NeonNumber.php | 7 +- Maths/PerfectNumber.php | 2 + Maths/PerfectSquare.php | 4 +- Maths/ProjectEuler/Problem1.php | 27 +------ Maths/ProjectEuler/Problem10.php | 6 +- Maths/ProjectEuler/Problem11.php | 21 +++-- Maths/ProjectEuler/Problem2.php | 23 +----- Maths/ProjectEuler/Problem3.php | 20 +---- Maths/ProjectEuler/Problem4.php | 11 +-- Maths/ProjectEuler/Problem5.php | 13 +-- Maths/ProjectEuler/Problem6.php | 3 + Maths/ProjectEuler/Problem7.php | 12 +-- Maths/ProjectEuler/Problem8.php | 35 +------- Maths/ProjectEuler/Problem9.php | 19 +---- .../NeuralNetworkPerceptronClassifier.php | 71 +++++++---------- Searches/BinarySearch.php | 24 +++--- Searches/ExponentialSearch.php | 16 ++-- Searches/FibonacciSearch.php | 3 + Searches/InterpolationSearch.php | 9 ++- Searches/JumpSearch.php | 6 +- Searches/LinearSearch.php | 6 +- Searches/LowerBound.php | 4 +- Searches/SentinelSearch.php | 11 ++- Searches/TernarySearch.php | 13 ++- Searches/TwoPointers.php | 15 ++-- Searches/UpperBound.php | 4 +- Sorting/ArrayKeysSort.php | 39 +++++---- Sorting/BubbleSort.php | 7 +- Sorting/BubbleSort2.php | 7 +- Sorting/CountSort.php | 4 +- Sorting/GnomeSort.php | 7 +- Sorting/HeapSort.php | 10 +-- Sorting/InsertionSort.php | 10 +-- Sorting/MergeSort.php | 12 +-- Sorting/QuickSort.php | 8 +- Sorting/RadixSort.php | 27 ++++--- Sorting/SelectionSort.php | 7 +- Sorting/ShellSort.php | 7 +- Strings/CheckAnagram.php | 9 +-- Strings/CheckPalindrome.php | 13 ++- Strings/CheckPalindrome2.php | 7 +- Strings/CountConsonants.php | 6 +- Strings/CountHomogenous.php | 5 +- Strings/CountSentences.php | 5 +- Strings/CountVowels.php | 10 +-- Strings/Distance.php | 10 +-- Strings/MaxCharacter.php | 6 +- Strings/ReverseString.php | 7 +- Strings/ReverseWords.php | 7 +- UPDATE_2026.md | 44 +++++++++++ Utils/ArrayHelpers.php | 6 +- Utils/ExecutionTime.php | 6 +- composer.json | 16 ++-- tests/Conversions/ConversionsTest.php | 28 +++---- tests/DataStructures/SinglyLinkedListTest.php | 13 +-- 121 files changed, 951 insertions(+), 881 deletions(-) create mode 100644 UPDATE_2026.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 35560791..45898880 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,9 @@ jobs: build: runs-on: ubuntu-latest + strategy: + matrix: + php-version: ['8.2', '8.3', '8.4', '8.5'] steps: - uses: actions/checkout@v4 @@ -17,7 +20,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.4' + php-version: ${{ matrix.php-version }} ini-values: xdebug.max_nesting_level=512 - name: Validate composer.json and composer.lock diff --git a/.github/workflows/code-style.yml b/.github/workflows/code-style.yml index e852dfc9..4230b3bd 100644 --- a/.github/workflows/code-style.yml +++ b/.github/workflows/code-style.yml @@ -16,10 +16,10 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.4' + php-version: '8.2' - name: Install dependencies - run: composer update --prefer-dist --no-progress --no-suggest + run: composer update --prefer-dist --no-progress - name: Run script run: vendor/bin/phpcs -n \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0b0abd8e..9d08400b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,22 +28,24 @@ Please help us keep our issue list small by adding fixes: #{$ISSUE_NO} to the co #### What is an Algorithm? An Algorithm is one or more functions (or classes) that: -* take one or more inputs, -* perform some internal calculations or data manipulations, -* return one or more outputs, -* have minimal side effects (Ex. print(), plot(), read(), write()). + +- take one or more inputs, +- perform some internal calculations or data manipulations, +- return one or more outputs, +- have minimal side effects (Ex. print(), plot(), read(), write()). Algorithms should be packaged in a way that would make it easy for readers to put them into larger programs. Algorithms should: -* have intuitive class and function names that make their purpose clear to readers -* use PHP naming conventions and intuitive variable names to ease comprehension -* be flexible to take different input values -* have PHP type hints for their input parameters and return values -* raise PHP exceptions (UnexpectedValueException, etc.) on erroneous input values -* have docstrings with clear explanations and/or URLs to source materials -* contain doctests that test both valid and erroneous input values -* return all calculation results instead of printing or plotting them + +- have intuitive class and function names that make their purpose clear to readers +- use PHP naming conventions and intuitive variable names to ease comprehension +- be flexible to take different input values +- have PHP type hints for their input parameters and return values +- raise PHP exceptions (UnexpectedValueException, etc.) on erroneous input values +- have docstrings with clear explanations and/or URLs to source materials +- contain doctests that test both valid and erroneous input values +- return all calculation results instead of printing or plotting them Algorithms in this repo should not be how-to examples for existing PHP packages. Instead, they should perform internal calculations or manipulations to convert input values into different output values. Those calculations or manipulations can use data types, classes, or functions of existing PHP packages but each algorithm in this repo should add unique value. @@ -51,8 +53,8 @@ Algorithms in this repo should not be how-to examples for existing PHP packages. We want your work to be readable by others; therefore, we encourage you to note the following: -- Please write in PHP 7.1+ -- Please put thought into naming of functions, classes, and variables. Help your reader by using __descriptive names__ that can help you to remove redundant comments +- Please write in PHP 8.2+ +- Please put thought into naming of functions, classes, and variables. Help your reader by using **descriptive names** that can help you to remove redundant comments - Single letter variable names are _old school_ so please avoid them unless their life only spans a few lines - Please follow the [PHP Basic Coding Standard](https://www.php-fig.org/psr/psr-12/) style guide. So functionNames should be camelCase, CONSTANTS in UPPER_CASE, Name\Spaces and ClassNames should follow an "autoloading" PSR, etc. @@ -66,13 +68,14 @@ We want your work to be readable by others; therefore, we encourage you to note - Avoid importing external libraries for basic algorithms. Only use them for complicated algorithms -- Ensure code is linted with phpcs, and passing all linting checks (vendor/bin/phpcs -n) +- Ensure code is strictly typed and passes static analysis (`composer phpstan`) +- Ensure code is properly linted and formatted (`vendor/bin/php-cs-fixer fix` and `vendor/bin/phpcs -n`) #### Other Standard While Submitting Your Work -- File extension for code should be `.php` +- File extension for code should be `.php` - After adding a new File/Directory, please make sure to update the [DIRECTORY.md](DIRECTORY.md) file with the details. -- If possible, follow the standard *within* the folder you are submitting to +- If possible, follow the standard _within_ the folder you are submitting to - If you have modified/added code work, make sure the code compiles before submitting - If you have modified/added documentation work, ensure your language is concise and contains no grammar errors - Add a corresponding explanation to [Algorithms-Explanation](https://github.com/TheAlgorithms/Algorithms-Explanation) (Optional but recommended). diff --git a/Ciphers/AtbashCipher.php b/Ciphers/AtbashCipher.php index 655365c4..e81869d7 100644 --- a/Ciphers/AtbashCipher.php +++ b/Ciphers/AtbashCipher.php @@ -1,5 +1,7 @@ ".-", "B" => "-...", "C" => "-.-.", @@ -47,17 +50,18 @@ function encode(string $text): string "8" => "---..", "9" => "----.", "0" => "-----", - " " => "/" - ); + " " => "/", + ]; $encodedText = ""; // Stores the encoded text foreach (str_split($text) as $c) { // Going through each character if (array_key_exists($c, $MORSE_CODE)) { // Checks if it is a valid character $encodedText .= $MORSE_CODE[$c] . " "; // Appends the correct character } else { - throw new \Exception("Invalid character: $c"); + throw new \Exception('Invalid character: ' . $c); } } + substr_replace($encodedText, "", -1); // Removes trailing space return $encodedText; } @@ -69,7 +73,8 @@ function encode(string $text): string */ function decode(string $text): string { - $MORSE_CODE = array( // An array containing morse code to text translations + $MORSE_CODE = [ + // An array containing morse code to text translations ".-" => "A", "-..." => "B", "-.-." => "C", @@ -106,18 +111,20 @@ function decode(string $text): string "---.." => "8", "----." => "9", "-----" => "0", - "/" => " " - ); + "/" => " ", + ]; $decodedText = ""; // Stores the decoded text foreach (explode(" ", $text) as $c) { // Going through each group - if (array_key_exists($c, $MORSE_CODE)) { // Checks if it is a valid character - $decodedText .= $MORSE_CODE[$c]; // Appends the correct character - } else { - if ($c) { // Makes sure that the string is not empty to prevent trailing spaces or extra spaces from breaking this - throw new \Exception("Invalid character: $c"); - } + if (array_key_exists($c, $MORSE_CODE)) { + // Checks if it is a valid character + $decodedText .= $MORSE_CODE[$c]; + // Appends the correct character + } elseif ($c !== '' && $c !== '0') { + // Makes sure that the string is not empty to prevent trailing spaces or extra spaces from breaking this + throw new \Exception('Invalid character: ' . $c); } } + return $decodedText; } diff --git a/Ciphers/RailfenceCipher.php b/Ciphers/RailfenceCipher.php index 683b8a09..334a5961 100644 --- a/Ciphers/RailfenceCipher.php +++ b/Ciphers/RailfenceCipher.php @@ -1,5 +1,7 @@ $rowIndex) { $lengths[$rowIndex]++; } + if ($balance > ($rails + ($rails - $rowIndex) - 2)) { $lengths[$rowIndex]++; } + $strings[] = substr($cipherMessage, $totalLengths, $lengths[$rowIndex]); $totalLengths += $lengths[$rowIndex]; } + // Convert the rows of characters to plain message $plainText = ''; while (strlen($plainText) < $textLength) { for ($charIndex = 0; $charIndex < $position; $charIndex++) { - if (isset($strings[$charIndex])) { - $index = $charIndex; - } else { - $index = $position - $charIndex; - } + $index = isset($strings[$charIndex]) ? $charIndex : $position - $charIndex; + $plainText .= substr($strings[$index], 0, 1); $strings[$index] = substr($strings[$index], 1); } } + return $plainText; } diff --git a/Ciphers/VignereCipher.php b/Ciphers/VignereCipher.php index d3bf1bf2..b0c732e9 100644 --- a/Ciphers/VignereCipher.php +++ b/Ciphers/VignereCipher.php @@ -1,5 +1,7 @@ $digit) { - $decimalNumber += $digit * pow(2, $index); + $decimalNumber += $digit * 2 ** $index; } return $decimalNumber; diff --git a/Conversions/DecimalToBinary.php b/Conversions/DecimalToBinary.php index 89d7accd..a591831c 100644 --- a/Conversions/DecimalToBinary.php +++ b/Conversions/DecimalToBinary.php @@ -1,15 +1,16 @@ 15, ]; - $hexDigits = str_split($hexNumber); + $hexDigits = str_split((string) $hexNumber); $hexDigits = array_reverse($hexDigits); foreach ($hexDigits as $power => $digit) { @@ -42,8 +44,10 @@ function hexToDecimal($hexNumber) if (!is_numeric($digit)) { $hexDigit = $decimalDigitMappings[$digit]; } - $decimalNumber += (pow(16, $power) * $hexDigit); + + $decimalNumber += (16 ** $power * $hexDigit); } + return $decimalNumber; } @@ -53,9 +57,8 @@ function hexToDecimal($hexNumber) * Hexadecimal Number. * * @param string $decimalNumber - * @return string */ -function decimalToHex($decimalNumber) +function decimalToHex($decimalNumber): string { $hexDigits = []; @@ -72,12 +75,14 @@ function decimalToHex($decimalNumber) throw new \Exception('Please pass a valid Decimal Number for Converting it to a Hexadecimal Number.'); } + $decimalNumber = (int) $decimalNumber; while ($decimalNumber > 0) { $remainder = ($decimalNumber % 16); - $decimalNumber /= 16; - if (empty($hexDigits) && 0 === $remainder) { + $decimalNumber = intdiv($decimalNumber, 16); + if ($hexDigits === [] && 0 === $remainder) { continue; } + $hexDigits[] = $remainder; } @@ -87,9 +92,7 @@ function decimalToHex($decimalNumber) if ($digit > 9) { $hexDigits[$index] = $hexDigitMappings[$digit]; } - } - - $hexNumber = ltrim(implode('', $hexDigits), '0'); // Connecting all the digits and removing leading zeroes. + } // Connecting all the digits and removing leading zeroes. - return $hexNumber; + return ltrim(implode('', $hexDigits), '0'); } diff --git a/Conversions/OctalToDecimal.php b/Conversions/OctalToDecimal.php index 8172de21..2df9faad 100644 --- a/Conversions/OctalToDecimal.php +++ b/Conversions/OctalToDecimal.php @@ -1,5 +1,7 @@ $digit) { - $decimalNumber += $digit * pow(8, $index); + $decimalNumber += $digit * 8 ** $index; } return $decimalNumber; @@ -36,10 +38,9 @@ function octalToDecimal($octalNumber) * Octal Number. * * @param string $decimalNumber - * @return string * @throws \Exception */ -function decimalToOctal($decimalNumber) +function decimalToOctal($decimalNumber): string { if (!is_numeric($decimalNumber)) { throw new \Exception('Please pass a valid Decimal Number for Converting it to an Octal Number.'); @@ -47,9 +48,10 @@ function decimalToOctal($decimalNumber) $octalNumber = ''; + $decimalNumber = (int) $decimalNumber; while ($decimalNumber > 0) { $octalNumber = ($decimalNumber % 8) . $octalNumber; - $decimalNumber /= 8; + $decimalNumber = intdiv($decimalNumber, 8); } return $octalNumber; diff --git a/Conversions/SpeedConversion.php b/Conversions/SpeedConversion.php index 1c8fddbe..d857c7d7 100644 --- a/Conversions/SpeedConversion.php +++ b/Conversions/SpeedConversion.php @@ -1,5 +1,7 @@ 1 knot which is equal to 1 nautical mile (1852 km/h) * The conversion is made using kilometers as base * - * @param float $speed - * @param string $unitFrom - * @param string $unitTo - * @return float * @throws \Exception */ -function convertSpeed(float $speed, string $unitFrom, string $unitTo) +function convertSpeed(float $speed, string $unitFrom, string $unitTo): float { $speedUnitsFrom = [ 'mph' => 1.609344, @@ -41,6 +39,7 @@ function convertSpeed(float $speed, string $unitFrom, string $unitTo) if (!is_numeric($speed)) { throw new \Exception("Please pass a valid speed number for converting it from one unit to another."); } + if (!in_array($unitFrom, $availableUnits) || !in_array($unitTo, $availableUnits)) { throw new \Exception("Please pass a valid speed unit.\n\nAvailable units: " . implode(', ', $availableUnits)); } diff --git a/Conversions/TemperatureConversions.php b/Conversions/TemperatureConversions.php index 1be1fb52..3aaf16c0 100644 --- a/Conversions/TemperatureConversions.php +++ b/Conversions/TemperatureConversions.php @@ -1,5 +1,7 @@ root = null; - $this->counter = 0; - } + private int $counter = 0; /** * Get the root node of the AVL Tree. @@ -40,7 +37,7 @@ public function getRoot(): ?AVLTreeNode * @param mixed $key The key of the node to retrieve. * @return ?AVLTreeNode The node with the specified key, or null if not found. */ - public function getNode($key): ?AVLTreeNode + public function getNode(mixed $key): ?AVLTreeNode { return $this->searchNode($this->root, $key); } @@ -59,7 +56,7 @@ public function size(): int * @param mixed $key The key to insert. * @param mixed $value The value associated with the key. */ - public function insert($key, $value): void + public function insert(mixed $key, mixed $value): void { $this->root = $this->insertNode($this->root, $key, $value); $this->counter++; @@ -70,7 +67,7 @@ public function insert($key, $value): void * * @param mixed $key The key of the node to delete. */ - public function delete($key): void + public function delete(mixed $key): void { $this->root = $this->deleteNode($this->root, $key); $this->counter--; @@ -82,10 +79,10 @@ public function delete($key): void * @param mixed $key The key to search for. * @return mixed The value associated with the key, or null if not found. */ - public function search($key) + public function search(mixed $key) { $node = $this->searchNode($this->root, $key); - return $node ? $node->value : null; + return $node instanceof \DataStructures\AVLTree\AVLTreeNode ? $node->value : null; } /** @@ -140,9 +137,9 @@ public function isBalanced(): bool * @param mixed $value The value to insert. * @return AVLTreeNode The new root of the subtree. */ - private function insertNode(?AVLTreeNode $node, $key, $value): AVLTreeNode + private function insertNode(?AVLTreeNode $node, mixed $key, mixed $value): AVLTreeNode { - if ($node === null) { + if (!$node instanceof \DataStructures\AVLTree\AVLTreeNode) { return new AVLTreeNode($key, $value); } @@ -165,9 +162,9 @@ private function insertNode(?AVLTreeNode $node, $key, $value): AVLTreeNode * @param mixed $key The key of the node to delete. * @return ?AVLTreeNode The new root of the subtree. */ - private function deleteNode(?AVLTreeNode $node, $key): ?AVLTreeNode + private function deleteNode(?AVLTreeNode $node, mixed $key): ?AVLTreeNode { - if ($node === null) { + if (!$node instanceof \DataStructures\AVLTree\AVLTreeNode) { return null; } @@ -176,10 +173,11 @@ private function deleteNode(?AVLTreeNode $node, $key): ?AVLTreeNode } elseif ($key > $node->key) { $node->right = $this->deleteNode($node->right, $key); } else { - if (!$node->left) { + if (!$node->left instanceof \DataStructures\AVLTree\AVLTreeNode) { return $node->right; } - if (!$node->right) { + + if (!$node->right instanceof \DataStructures\AVLTree\AVLTreeNode) { return $node->left; } @@ -200,15 +198,16 @@ private function deleteNode(?AVLTreeNode $node, $key): ?AVLTreeNode * @param mixed $key The key to search for. * @return ?AVLTreeNode The node with the specified key, or null if not found. */ - private function searchNode(?AVLTreeNode $node, $key): ?AVLTreeNode + private function searchNode(?AVLTreeNode $node, mixed $key): ?AVLTreeNode { - if ($node === null) { + if (!$node instanceof \DataStructures\AVLTree\AVLTreeNode) { return null; } - if ($key < $node->key) { return $this->searchNode($node->left, $key); - } elseif ($key > $node->key) { + } + + if ($key > $node->key) { return $this->searchNode($node->right, $key); } else { return $node; @@ -223,12 +222,12 @@ private function searchNode(?AVLTreeNode $node, $key): ?AVLTreeNode */ private function isBalancedHelper(?AVLTreeNode $node): bool { - if ($node === null) { + if (!$node instanceof \DataStructures\AVLTree\AVLTreeNode) { return true; } - $leftHeight = $node->left ? $node->left->height : 0; - $rightHeight = $node->right ? $node->right->height : 0; + $leftHeight = $node->left instanceof \DataStructures\AVLTree\AVLTreeNode ? $node->left->height : 0; + $rightHeight = $node->right instanceof \DataStructures\AVLTree\AVLTreeNode ? $node->right->height : 0; $balanceFactor = abs($leftHeight - $rightHeight); if ($balanceFactor > 1) { @@ -250,6 +249,7 @@ private function balance(?AVLTreeNode $node): ?AVLTreeNode if ($node->left && $node->left->balanceFactor() < 0) { $node->left = $this->rotateLeft($node->left); } + return $this->rotateRight($node); } @@ -257,6 +257,7 @@ private function balance(?AVLTreeNode $node): ?AVLTreeNode if ($node->right && $node->right->balanceFactor() > 0) { $node->right = $this->rotateRight($node->right); } + return $this->rotateLeft($node); } @@ -307,9 +308,10 @@ private function rotateRight(AVLTreeNode $node): AVLTreeNode */ private function getMinNode(AVLTreeNode $node): AVLTreeNode { - while ($node->left) { + while ($node->left instanceof \DataStructures\AVLTree\AVLTreeNode) { $node = $node->left; } + return $node; } @@ -325,15 +327,13 @@ public function serialize(): string /** * Recursively serializes the AVL Tree. - * - * @param AVLTreeNode|null $node - * @return array */ private function serializeTree(?AVLTreeNode $node): array { - if ($node === null) { + if (!$node instanceof \DataStructures\AVLTree\AVLTreeNode) { return []; } + return [ 'key' => $node->key, 'value' => $node->value, @@ -363,7 +363,7 @@ public function deserialize(string $data): void */ private function deserializeTree(array $data): ?AVLTreeNode { - if (empty($data)) { + if ($data === []) { return null; } @@ -383,7 +383,7 @@ private function deserializeTree(array $data): ?AVLTreeNode */ private function updateNodeCount(?AVLTreeNode $node): void { - if ($node !== null) { + if ($node instanceof \DataStructures\AVLTree\AVLTreeNode) { $this->counter++; $this->updateNodeCount($node->left); $this->updateNodeCount($node->right); diff --git a/DataStructures/AVLTree/AVLTreeNode.php b/DataStructures/AVLTree/AVLTreeNode.php index 2d21c6a1..f614b964 100644 --- a/DataStructures/AVLTree/AVLTreeNode.php +++ b/DataStructures/AVLTree/AVLTreeNode.php @@ -1,5 +1,7 @@ key = $key; - $this->value = $value; - $this->left = $left; - $this->right = $right; - $this->height = 1; // New node is initially at height 1 + // New node is initially at height 1 } public function updateHeight(): void { - $leftHeight = $this->left ? $this->left->height : 0; - $rightHeight = $this->right ? $this->right->height : 0; + $leftHeight = $this->left instanceof \DataStructures\AVLTree\AVLTreeNode ? $this->left->height : 0; + $rightHeight = $this->right instanceof \DataStructures\AVLTree\AVLTreeNode ? $this->right->height : 0; $this->height = max($leftHeight, $rightHeight) + 1; } public function balanceFactor(): int { - $leftHeight = $this->left ? $this->left->height : 0; - $rightHeight = $this->right ? $this->right->height : 0; + $leftHeight = $this->left instanceof \DataStructures\AVLTree\AVLTreeNode ? $this->left->height : 0; + $rightHeight = $this->right instanceof \DataStructures\AVLTree\AVLTreeNode ? $this->right->height : 0; return $leftHeight - $rightHeight; } } diff --git a/DataStructures/AVLTree/TreeTraversal.php b/DataStructures/AVLTree/TreeTraversal.php index b6812683..d01082f2 100644 --- a/DataStructures/AVLTree/TreeTraversal.php +++ b/DataStructures/AVLTree/TreeTraversal.php @@ -1,5 +1,7 @@ left)); $result[] = [$node->key => $node->value]; $result = array_merge($result, self::inOrder($node->right)); } + return $result; } @@ -34,11 +37,12 @@ public static function inOrder(?AVLTreeNode $node): array public static function preOrder(?AVLTreeNode $node): array { $result = []; - if ($node !== null) { + if ($node instanceof \DataStructures\AVLTree\AVLTreeNode) { $result[] = [$node->key => $node->value]; $result = array_merge($result, self::preOrder($node->left)); $result = array_merge($result, self::preOrder($node->right)); } + return $result; } @@ -49,11 +53,12 @@ public static function preOrder(?AVLTreeNode $node): array public static function postOrder(?AVLTreeNode $node): array { $result = []; - if ($node !== null) { + if ($node instanceof \DataStructures\AVLTree\AVLTreeNode) { $result = array_merge($result, self::postOrder($node->left)); $result = array_merge($result, self::postOrder($node->right)); $result[] = [$node->key => $node->value]; } + return $result; } @@ -63,14 +68,14 @@ public static function postOrder(?AVLTreeNode $node): array public static function breadthFirst(?AVLTreeNode $root): array { $result = []; - if ($root === null) { + if (!$root instanceof \DataStructures\AVLTree\AVLTreeNode) { return $result; } $queue = []; $queue[] = $root; - while (!empty($queue)) { + while ($queue !== []) { $currentNode = array_shift($queue); $result[] = [$currentNode->key => $currentNode->value]; diff --git a/DataStructures/BinarySearchTree/BSTNode.php b/DataStructures/BinarySearchTree/BSTNode.php index 1b180718..a24462a1 100644 --- a/DataStructures/BinarySearchTree/BSTNode.php +++ b/DataStructures/BinarySearchTree/BSTNode.php @@ -1,5 +1,7 @@ key = $key; - $this->value = $value; - $this->left = null; - $this->right = null; - $this->parent = null; } public function isRoot(): bool { - return $this->parent === null; + return !$this->parent instanceof \DataStructures\BinarySearchTree\BSTNode; } public function isLeaf(): bool { - return $this->left === null && $this->right === null; + return !$this->left instanceof \DataStructures\BinarySearchTree\BSTNode && !$this->right instanceof \DataStructures\BinarySearchTree\BSTNode; } public function getChildren(): array @@ -51,14 +45,17 @@ public function getChildren(): array } $children = []; - if ($this->left !== null) { + if ($this->left instanceof \DataStructures\BinarySearchTree\BSTNode) { $children['left'] = $this->left; } - if ($this->right !== null) { + + if ($this->right instanceof \DataStructures\BinarySearchTree\BSTNode) { $children['right'] = $this->right; } + return $children; } + public function getChildrenCount(): int { return count($this->getChildren()); diff --git a/DataStructures/BinarySearchTree/BSTree.php b/DataStructures/BinarySearchTree/BSTree.php index 0fded5e7..5ade0a4a 100644 --- a/DataStructures/BinarySearchTree/BSTree.php +++ b/DataStructures/BinarySearchTree/BSTree.php @@ -1,5 +1,7 @@ $value) { $this->insert($key, $value); // Build the tree from an array of key-value pairs } + parent::setTraversalType($traversalType); } + /** * Get the root of the Splay Tree. * @@ -46,7 +51,7 @@ public function size(): int public function isEmpty(): bool { - return $this->root === null; + return !$this->root instanceof \DataStructures\BinarySearchTree\BSTNode; } /** @@ -63,7 +68,7 @@ public function insert(int $key, $value): ?BSTNode private function insertNode(?BSTNode &$rootPtr, int $key, $value): void { - if ($rootPtr === null) { + if (!$rootPtr instanceof \DataStructures\BinarySearchTree\BSTNode) { $rootPtr = new BSTNode($key, $value); return; } @@ -87,15 +92,16 @@ private function insertNode(?BSTNode &$rootPtr, int $key, $value): void public function remove(int $key): ?BSTNode { $discardedNode = $this->removeNode($this->root, $key); - if ($discardedNode !== null) { + if ($discardedNode instanceof \DataStructures\BinarySearchTree\BSTNode) { $this->counter--; } + return $discardedNode; } private function removeNode(?BSTNode &$rootPtr, int $key): ?BSTNode { - if ($rootPtr === null) { + if (!$rootPtr instanceof \DataStructures\BinarySearchTree\BSTNode) { return null; } @@ -109,6 +115,7 @@ private function removeNode(?BSTNode &$rootPtr, int $key): ?BSTNode ? $this->handleNodeWithTwoChildren($rootPtr) : $this->handleNodeWithSingleOrZeroChild($rootPtr); } + return $discardedNode; } @@ -152,7 +159,7 @@ private function handleNodeWithSingleOrZeroChild(BSTNode &$rootPtr): ?BSTNode } // Update the parent reference for the new child node - if ($rootPtr !== null) { + if ($rootPtr instanceof \DataStructures\BinarySearchTree\BSTNode) { $rootPtr->parent = $discard->parent; } @@ -166,13 +173,13 @@ private function handleNodeWithSingleOrZeroChild(BSTNode &$rootPtr): ?BSTNode */ public function minNode(?BSTNode $node): ?BSTNode { - if ($node === null) { + if (!$node instanceof \DataStructures\BinarySearchTree\BSTNode) { return null; } - return $node->left === null - ? $node - : $this->minNode($node->left); + return $node->left instanceof \DataStructures\BinarySearchTree\BSTNode + ? $this->minNode($node->left) + : $node; } /** @@ -191,13 +198,14 @@ public function search(int $key): ?BSTNode private function searchNode(?BSTNode $node, int $key): ?BSTNode { - if ($node === null) { + if (!$node instanceof \DataStructures\BinarySearchTree\BSTNode) { return null; } - if ($key === $node->key) { return $node; - } elseif ($key < $node->key) { + } + + if ($key < $node->key) { return $this->searchNode($node->left, $key); } else { return $this->searchNode($node->right, $key); @@ -214,13 +222,14 @@ private function searchNode(?BSTNode $node, int $key): ?BSTNode */ public function isFound(?BSTNode $node, int $key): bool { - if ($node === null) { + if (!$node instanceof \DataStructures\BinarySearchTree\BSTNode) { return false; } - if ($key === $node->key) { return true; - } elseif ($key < $node->key) { + } + + if ($key < $node->key) { return $this->isFound($node->left, $key); } else { return $this->isFound($node->right, $key); @@ -238,9 +247,9 @@ public function isFound(?BSTNode $node, int $key): bool */ public function getDepth(BSTNode $node): int { - return $node->parent === null - ? 0 - : 1 + $this->getDepth($node->parent); + return $node->parent instanceof \DataStructures\BinarySearchTree\BSTNode + ? 1 + $this->getDepth($node->parent) + : 0; } /** @@ -257,12 +266,14 @@ public function getHeight(BSTNode $node): int if ($node->isLeaf()) { return 0; } + $height = 0; $childrenList = $node->getChildren(); foreach ($childrenList as $childNode) { $height = max($height, $this->getHeight($childNode)); } + return 1 + $height; } @@ -316,9 +327,10 @@ public function serialize(): string */ private function serializeTree(?BSTNode $node): array { - if ($node === null) { + if (!$node instanceof \DataStructures\BinarySearchTree\BSTNode) { return []; } + return [ 'key' => $node->key, 'value' => $node->value, @@ -352,7 +364,7 @@ public function deserialize(string $data): BSTree */ private function deserializeTree(array $data, ?BSTNode $parent): ?BSTNode { - if (empty($data)) { + if ($data === []) { return null; } @@ -364,12 +376,13 @@ private function deserializeTree(array $data, ?BSTNode $parent): ?BSTNode return $node; } + /** * Recursively updates the BST size after deserialization. */ private function updateNodeCount(?BSTNode $node): void { - if ($node !== null) { + if ($node instanceof \DataStructures\BinarySearchTree\BSTNode) { $this->counter++; $this->updateNodeCount($node->left); $this->updateNodeCount($node->right); diff --git a/DataStructures/BinarySearchTree/BinaryTreeTraversal.php b/DataStructures/BinarySearchTree/BinaryTreeTraversal.php index a312dacc..3380f289 100644 --- a/DataStructures/BinarySearchTree/BinaryTreeTraversal.php +++ b/DataStructures/BinarySearchTree/BinaryTreeTraversal.php @@ -1,5 +1,7 @@ traversalType) { - case self::PRE_ORDER: - $this->preOrderIterator(static::getRoot()); - break; - - case self::POST_ORDER: - $this->postOrderIterator(static::getRoot()); - break; - - case self::IN_ORDER: - default: - $this->inOrderIterator(static::getRoot()); - } + match ($this->traversalType) { + self::PRE_ORDER => $this->preOrderIterator(static::getRoot()), + self::POST_ORDER => $this->postOrderIterator(static::getRoot()), + default => $this->inOrderIterator(static::getRoot()), + }; } /** @@ -63,11 +63,12 @@ private function loadTraversedNodes(): void protected function inOrder(?BSTNode $node): array { $result = []; - if ($node !== null) { + if ($node instanceof \DataStructures\BinarySearchTree\BSTNode) { $result += $this->inOrder($node->left); $result[$node->key] = $node->value; $result += $this->inOrder($node->right); } + return $result; } @@ -77,11 +78,12 @@ protected function inOrder(?BSTNode $node): array protected function preOrder(?BSTNode $node): array { $result = []; - if ($node !== null) { + if ($node instanceof \DataStructures\BinarySearchTree\BSTNode) { $result[$node->key] = $node->value; $result += $this->preOrder($node->left); $result += $this->preOrder($node->right); } + return $result; } @@ -91,11 +93,12 @@ protected function preOrder(?BSTNode $node): array protected function postOrder(?BSTNode $node): array { $result = []; - if ($node !== null) { + if ($node instanceof \DataStructures\BinarySearchTree\BSTNode) { $result += $this->postOrder($node->left); $result += $this->postOrder($node->right); $result[$node->key] = $node->value; } + return $result; } @@ -112,7 +115,7 @@ protected function breadthFirst(?BSTNode $node): array $queue = []; $queue[] = $node; - while (!empty($queue)) { + while ($queue !== []) { $currentNode = array_shift($queue); $result[$currentNode->key] = $currentNode->value; @@ -124,6 +127,7 @@ protected function breadthFirst(?BSTNode $node): array $queue[] = $currentNode->right; } } + return $result; } @@ -176,29 +180,31 @@ public function valid(): bool */ private function inOrderIterator(?BSTNode $node): void { - if ($node !== null) { + if ($node instanceof \DataStructures\BinarySearchTree\BSTNode) { $this->inOrderIterator($node->left); $this->iterationNodes[] = $node; $this->inOrderIterator($node->right); } } + /** * Helper function to traverse the tree in-order and fill the $preOrderNodes array. */ private function preOrderIterator(?BSTNode $node): void { - if ($node !== null) { + if ($node instanceof \DataStructures\BinarySearchTree\BSTNode) { $this->iterationNodes[] = $node; $this->preOrderIterator($node->left); $this->preOrderIterator($node->right); } } + /** * Helper function to traverse the tree in-order and fill the $postOrderNodes array. */ private function postOrderIterator(?BSTNode $node): void { - if ($node !== null) { + if ($node instanceof \DataStructures\BinarySearchTree\BSTNode) { $this->postOrderIterator($node->left); $this->postOrderIterator($node->right); $this->iterationNodes[] = $node; diff --git a/DataStructures/BinarySearchTree/DuplicateKeyException.php b/DataStructures/BinarySearchTree/DuplicateKeyException.php index 37cf1669..79abd859 100644 --- a/DataStructures/BinarySearchTree/DuplicateKeyException.php +++ b/DataStructures/BinarySearchTree/DuplicateKeyException.php @@ -1,5 +1,7 @@ value = $value; - $this->left = $left; - $this->right = $right; } - - public $value; - public ?BinaryTreeNode $left; - public ?BinaryTreeNode $right; } diff --git a/DataStructures/CompareBinaryTree/CompareBinaryTree.php b/DataStructures/CompareBinaryTree/CompareBinaryTree.php index d4def6e4..61ba448f 100644 --- a/DataStructures/CompareBinaryTree/CompareBinaryTree.php +++ b/DataStructures/CompareBinaryTree/CompareBinaryTree.php @@ -1,5 +1,7 @@ value !== $b->value) { return false; } + return $this->areTreesEqual($a->left, $b->left) && $this->areTreesEqual($a->right, $b->right); } diff --git a/DataStructures/DisjointSets/DisjointSet.php b/DataStructures/DisjointSets/DisjointSet.php index 8046ae55..e56f0130 100644 --- a/DataStructures/DisjointSets/DisjointSet.php +++ b/DataStructures/DisjointSets/DisjointSet.php @@ -1,5 +1,7 @@ parent = $this->findSet($node->parent); } + return $node->parent; } diff --git a/DataStructures/DisjointSets/DisjointSetNode.php b/DataStructures/DisjointSets/DisjointSetNode.php index c8b885e1..4a6b4107 100644 --- a/DataStructures/DisjointSets/DisjointSetNode.php +++ b/DataStructures/DisjointSets/DisjointSetNode.php @@ -1,5 +1,7 @@ data = $data; - $this->rank = 0; $this->parent = $this; // Initialize parent to itself } } diff --git a/DataStructures/DoublyLinkedList.php b/DataStructures/DoublyLinkedList.php index 42a423b3..ebcc41f5 100644 --- a/DataStructures/DoublyLinkedList.php +++ b/DataStructures/DoublyLinkedList.php @@ -1,21 +1,17 @@ head = null; - $this->tail = null; - } + public ?Node $tail = null; // Destructor public function __destruct() @@ -30,7 +26,7 @@ public function append($data): void $newNode = new Node($data); // If the list is empty, set the head and tail to the new node - if ($this->head === null) { + if (!$this->head instanceof \Node) { $this->head = $newNode; $this->tail = $newNode; return; @@ -52,7 +48,7 @@ public function insert($data, $position): void $newNode = new Node($data); // If the list is empty, set the head and tail to the new node - if ($this->head === null) { + if (!$this->head instanceof \Node) { $this->head = $newNode; $this->tail = $newNode; return; @@ -77,7 +73,7 @@ public function insert($data, $position): void // Set the tail's next node to the new node // Set the new node's previous node to the tail // Set the tail to the new node - if ($current === null) { + if (!$current instanceof \Node) { $this->tail->next = $newNode; $newNode->prev = $this->tail; $this->tail = $newNode; @@ -102,7 +98,7 @@ public function insert($data, $position): void public function delete($data): void { // If the list is empty, return - if ($this->head === null) { + if (!$this->head instanceof \Node) { return; } @@ -119,7 +115,7 @@ public function delete($data): void $current = $this->head; // Loop through the list until we reach the end of the list - while ($current !== null) { + while ($current instanceof \Node) { // If the current node's data is the data we're looking for // Set the current node's previous node's next node to the current node's next node // Set the current node's next node's previous node to the current node's previous node @@ -138,7 +134,7 @@ public function delete($data): void public function deleteAt($position): void { // If the list is empty, return - if ($this->head === null) { + if (!$this->head instanceof \Node) { return; } @@ -159,7 +155,7 @@ public function deleteAt($position): void // If the current node is null, we've reached the end of the list // Set the tail to the current node's previous node // Set the tail's next node to null - if ($current === null) { + if (!$current instanceof \Node) { $this->tail = $current->prev; $this->tail->next = null; return; @@ -179,7 +175,7 @@ public function deleteAt($position): void public function printList(): void { // If the list is empty, return - if ($this->head === null) { + if (!$this->head instanceof \Node) { return; } @@ -187,7 +183,7 @@ public function printList(): void $current = $this->head; // Loop through the list until we reach the end of the list - while ($current !== null) { + while ($current instanceof \Node) { // Print the current node's data echo $current->data . "\n"; @@ -200,7 +196,7 @@ public function printList(): void public function printListReverse(): void { // If the list is empty, return - if ($this->head === null) { + if (!$this->head instanceof \Node) { return; } @@ -208,7 +204,7 @@ public function printListReverse(): void $current = $this->tail; // Loop through the list until we reach the beginning of the list - while ($current !== null) { + while ($current instanceof \Node) { // Print the current node's data echo $current->data . "\n"; @@ -221,7 +217,7 @@ public function printListReverse(): void public function reverse(): void { // If the list is empty, return - if ($this->head === null) { + if (!$this->head instanceof \Node) { return; } @@ -229,7 +225,7 @@ public function reverse(): void $current = $this->head; // Loop through the list until we reach the end of the list - while ($current !== null) { + while ($current instanceof \Node) { // Set the temp node to the current node's next node $temp = $current->next; @@ -257,7 +253,7 @@ public function reverse(): void public function length(): int { // If the list is empty, return 0 - if ($this->head === null) { + if (!$this->head instanceof \Node) { return 0; } @@ -268,7 +264,7 @@ public function length(): int $length = 0; // Loop through the list until we reach the end of the list - while ($current !== null) { + while ($current instanceof \Node) { // Increment the length $length++; @@ -284,7 +280,7 @@ public function length(): int public function search($data): ?Node { // If the list is empty, return null - if ($this->head === null) { + if (!$this->head instanceof \Node) { return null; } @@ -292,7 +288,7 @@ public function search($data): ?Node $current = $this->head; // Loop through the list until we reach the end of the list - while ($current !== null) { + while ($current instanceof \Node) { // If the current node's data is the data we're looking for, return the current node if ($current->data === $data) { return $current; @@ -310,19 +306,15 @@ public function search($data): ?Node public function isEmpty(): bool { // If the head is null, return true - if ($this->head === null) { - return true; - } - // Otherwise, return false - return false; + return !$this->head instanceof \Node; } // To String public function __toString(): string { // If the list is empty, return an empty string - if ($this->head === null) { + if (!$this->head instanceof \Node) { return ''; } @@ -333,12 +325,12 @@ public function __toString(): string $string = ''; // Loop through the list until we reach the end of the list - while ($current !== null) { + while ($current instanceof \Node) { // Append the current node's data to the string $string .= $current->data; // If the current node's next node is not null, append a comma and a space to the string - if ($current->next !== null) { + if ($current->next instanceof \Node) { $string .= ', '; } @@ -354,7 +346,7 @@ public function __toString(): string public function toArray(): array { // If the list is empty, return an empty array - if ($this->head === null) { + if (!$this->head instanceof \Node) { return []; } @@ -365,7 +357,7 @@ public function toArray(): array $array = []; // Loop through the list until we reach the end of the list - while ($current !== null) { + while ($current instanceof \Node) { // Append the current node's data to the array $array[] = $current->data; diff --git a/DataStructures/InvertBinaryTree/BinaryTree.php b/DataStructures/InvertBinaryTree/BinaryTree.php index 38419351..2cac465c 100644 --- a/DataStructures/InvertBinaryTree/BinaryTree.php +++ b/DataStructures/InvertBinaryTree/BinaryTree.php @@ -1,14 +1,18 @@ left = $left; return $this; @@ -19,7 +23,7 @@ public function getLeft(): ?BinaryTree return $this->left; } - public function setRight(?BinaryTree $right) + public function setRight(?BinaryTree $right): static { $this->right = $right; return $this; @@ -30,7 +34,7 @@ public function getRight(): ?BinaryTree return $this->right; } - public function setValue($value) + public function setValue($value): static { $this->value = $value; return $this; diff --git a/DataStructures/InvertBinaryTree/InvertBinaryTree.php b/DataStructures/InvertBinaryTree/InvertBinaryTree.php index 346f74c1..b51768f6 100644 --- a/DataStructures/InvertBinaryTree/InvertBinaryTree.php +++ b/DataStructures/InvertBinaryTree/InvertBinaryTree.php @@ -1,5 +1,7 @@ getLeft(); $b->setLeft($b->getRight()); $b->setRight($tmp); diff --git a/DataStructures/Node.php b/DataStructures/Node.php index e7178d08..6753edcd 100644 --- a/DataStructures/Node.php +++ b/DataStructures/Node.php @@ -1,17 +1,18 @@ data = $data; } } diff --git a/DataStructures/Queue.php b/DataStructures/Queue.php index 360e0acc..08f27c69 100644 --- a/DataStructures/Queue.php +++ b/DataStructures/Queue.php @@ -1,20 +1,17 @@ elements = []; - $this->count = 0; - $this->lowestCount = 0; - } + private int $count = 0; + + private int $lowestCount = 0; public function enqueue($element): void { @@ -69,10 +66,10 @@ public function toString(string $delimiter = ''): string return ''; } - $result = "{$this->elements[$this->lowestCount]}"; + $result = $this->elements[$this->lowestCount]; for ($i = $this->lowestCount + 1; $i < $this->count; $i++) { - $result .= "{$delimiter}{$this->elements[$i]}"; + $result .= $delimiter . $this->elements[$i]; } return $result; diff --git a/DataStructures/ReverseLinkedList/LinkedListItem.php b/DataStructures/ReverseLinkedList/LinkedListItem.php index 1e2ae822..b23a619e 100644 --- a/DataStructures/ReverseLinkedList/LinkedListItem.php +++ b/DataStructures/ReverseLinkedList/LinkedListItem.php @@ -1,14 +1,18 @@ next = $next; return $this; @@ -19,7 +23,7 @@ public function getNext(): ?LinkedListItem return $this->next; } - public function setPrev(?LinkedListItem $prev) + public function setPrev(?LinkedListItem $prev): static { $this->prev = $prev; return $this; @@ -30,7 +34,7 @@ public function getPrev(): ?LinkedListItem return $this->prev; } - public function setValue($value) + public function setValue($value): static { $this->value = $value; return $this; diff --git a/DataStructures/ReverseLinkedList/ReverseLinkedList.php b/DataStructures/ReverseLinkedList/ReverseLinkedList.php index cde6384b..2b3de25b 100644 --- a/DataStructures/ReverseLinkedList/ReverseLinkedList.php +++ b/DataStructures/ReverseLinkedList/ReverseLinkedList.php @@ -1,5 +1,7 @@ setNext(null); while (true) { $item->setPrev($next); - if (! $next) { + if (!$next instanceof \DataStructures\ReverseLinkedList\LinkedListItem) { return $item; } + $nextNext = $next->getNext(); $next->setNext($item); $item = $next; diff --git a/DataStructures/SegmentTree/SegmentTree.php b/DataStructures/SegmentTree/SegmentTree.php index fbc39a1f..97be4866 100644 --- a/DataStructures/SegmentTree/SegmentTree.php +++ b/DataStructures/SegmentTree/SegmentTree.php @@ -1,5 +1,7 @@ max($a, $b)); * - * @param array $arr The input array for the segment tree + * @param array $currentArray The input array for the segment tree * @param callable|null $callback Optional callback function for custom aggregation logic. * @throws InvalidArgumentException if the array is empty, contains non-numeric values, or is associative. */ - public function __construct(array $arr, callable $callback = null) + public function __construct(private array $currentArray, callable $callback = null) { - $this->currentArray = $arr; $this->arraySize = count($this->currentArray); $this->callback = $callback; @@ -47,7 +49,13 @@ public function __construct(array $arr, callable $callback = null) private function isUnsupportedArray(): bool { - return empty($this->currentArray) || $this->isNonNumeric() || $this->isAssociative(); + if ($this->currentArray === []) { + return true; + } + if ($this->isNonNumeric()) { + return true; + } + return $this->isAssociative(); } /** @@ -55,7 +63,7 @@ private function isUnsupportedArray(): bool */ private function isNonNumeric(): bool { - return !array_reduce($this->currentArray, fn($carry, $item) => $carry && is_numeric($item), true); + return !array_reduce($this->currentArray, fn ($carry, $item): bool => $carry && is_numeric($item), true); } /** @@ -92,14 +100,14 @@ public function getCurrentArray(): array */ private function buildTree(array $arr, int $start, int $end): SegmentTreeNode { - // Leaf node - if ($start == $end) { + // Leaf node + if ($start === $end) { return new SegmentTreeNode($start, $end, $arr[$start]); } $mid = $start + (int)(($end - $start) / 2); - // Recursively build left and right children + // Recursively build left and right children $leftChild = $this->buildTree($arr, $start, $mid); $rightChild = $this->buildTree($arr, $mid + 1, $end); @@ -107,7 +115,7 @@ private function buildTree(array $arr, int $start, int $end): SegmentTreeNode ? ($this->callback)($leftChild->value, $rightChild->value) : $leftChild->value + $rightChild->value); - // Link the children to the parent node + // Link the children to the parent node $node->left = $leftChild; $node->right = $rightChild; @@ -125,9 +133,10 @@ private function buildTree(array $arr, int $start, int $end): SegmentTreeNode public function query(int $start, int $end) { if ($start > $end || $start < 0 || $end > ($this->root->end)) { - throw new OutOfBoundsException("Index out of bounds: start = $start, end = $end. + throw new OutOfBoundsException("Index out of bounds: start = {$start}, end = {$end}. Must be between 0 and " . ($this->arraySize - 1)); } + return $this->queryTree($this->root, $start, $end); } @@ -141,19 +150,19 @@ public function query(int $start, int $end) */ private function queryTree(SegmentTreeNode $node, int $start, int $end) { - if ($node->start == $start && $node->end == $end) { + if ($node->start === $start && $node->end === $end) { return $node->value; } $mid = $node->start + (int)(($node->end - $node->start) / 2); - // Determine which segment of the tree to query + // Determine which segment of the tree to query if ($end <= $mid) { return $this->queryTree($node->left, $start, $end); // Query left child } elseif ($start > $mid) { return $this->queryTree($node->right, $start, $end); // Query right child } else { - // Split query between left and right children + // Split query between left and right children $leftResult = $this->queryTree($node->left, $start, $mid); $rightResult = $this->queryTree($node->right, $mid + 1, $end); @@ -173,7 +182,7 @@ private function queryTree(SegmentTreeNode $node, int $start, int $end) public function update(int $index, int $value): void { if ($index < 0 || $index >= $this->arraySize) { - throw new OutOfBoundsException("Index out of bounds: $index. Must be between 0 and " + throw new OutOfBoundsException(sprintf('Index out of bounds: %d. Must be between 0 and ', $index) . ($this->arraySize - 1)); } @@ -190,22 +199,22 @@ public function update(int $index, int $value): void */ private function updateTree(SegmentTreeNode $node, int $index, $value): void { - // Leaf node - if ($node->start == $node->end) { + // Leaf node + if ($node->start === $node->end) { $node->value = $value; return; } $mid = $node->start + (int)(($node->end - $node->start) / 2); - // Decide whether to go to the left or right child + // Decide whether to go to the left or right child if ($index <= $mid) { $this->updateTree($node->left, $index, $value); } else { $this->updateTree($node->right, $index, $value); } - // Recompute the value of the current node after the update + // Recompute the value of the current node after the update $node->value = $this->callback ? ($this->callback)($node->left->value, $node->right->value) : $node->left->value + $node->right->value; @@ -222,11 +231,12 @@ private function updateTree(SegmentTreeNode $node, int $index, $value): void public function rangeUpdate(int $start, int $end, $value): void { if ($start < 0 || $end >= $this->arraySize || $start > $end) { - throw new OutOfBoundsException("Invalid range: start = $start, end = $end."); + throw new OutOfBoundsException(sprintf('Invalid range: start = %d, end = %d.', $start, $end)); } + $this->rangeUpdateTree($this->root, $start, $end, $value); - // Update the original array to reflect the range update + // Update the original array to reflect the range update $this->currentArray = array_replace($this->currentArray, array_fill_keys(range($start, $end), $value)); } @@ -240,26 +250,26 @@ public function rangeUpdate(int $start, int $end, $value): void */ private function rangeUpdateTree(SegmentTreeNode $node, int $start, int $end, $value): void { - // Leaf node - if ($node->start == $node->end) { + // Leaf node + if ($node->start === $node->end) { $node->value = $value; return; } $mid = $node->start + (int)(($node->end - $node->start) / 2); - // Determine which segment of the tree to update (Left, Right, Split respectively) + // Determine which segment of the tree to update (Left, Right, Split respectively) if ($end <= $mid) { $this->rangeUpdateTree($node->left, $start, $end, $value); // Entire range is in the left child } elseif ($start > $mid) { $this->rangeUpdateTree($node->right, $start, $end, $value); // Entire range is in the right child } else { - // Range is split between left and right children + // Range is split between left and right children $this->rangeUpdateTree($node->left, $start, $mid, $value); $this->rangeUpdateTree($node->right, $mid + 1, $end, $value); } - // Recompute the value of the current node after the update + // Recompute the value of the current node after the update $node->value = $this->callback ? ($this->callback)($node->left->value, $node->right->value) : $node->left->value + $node->right->value; @@ -283,9 +293,10 @@ public function serialize(): string */ private function serializeTree(?SegmentTreeNode $node): array { - if ($node === null) { + if (!$node instanceof \DataStructures\SegmentTree\SegmentTreeNode) { return []; } + return [ 'start' => $node->start, 'end' => $node->end, @@ -320,9 +331,10 @@ public static function deserialize(string $data): self */ private function deserializeTree(array $data): ?SegmentTreeNode { - if (empty($data)) { + if ($data === []) { return null; } + $node = new SegmentTreeNode($data['start'], $data['end'], $data['value']); $node->left = $this->deserializeTree($data['left']); diff --git a/DataStructures/SegmentTree/SegmentTreeNode.php b/DataStructures/SegmentTree/SegmentTreeNode.php index bb017c67..835f217b 100644 --- a/DataStructures/SegmentTree/SegmentTreeNode.php +++ b/DataStructures/SegmentTree/SegmentTreeNode.php @@ -1,5 +1,7 @@ start = $start; - $this->end = $end; - $this->value = $value; - $this->left = null; - $this->right = null; } } diff --git a/DataStructures/SinglyLinkedList.php b/DataStructures/SinglyLinkedList.php index b7a97bce..fd802a2f 100644 --- a/DataStructures/SinglyLinkedList.php +++ b/DataStructures/SinglyLinkedList.php @@ -1,22 +1,22 @@ data = $data; } public function append($data): void { $current = $this; - while ($current instanceof SinglyLinkedList && isset($current->next)) { + while ($current instanceof SinglyLinkedList && $current->next instanceof \SinglyLinkedList) { $current = $current->next; } @@ -30,7 +30,7 @@ public function delete($data): SinglyLinkedList return $current->next; } - while ($current instanceof SinglyLinkedList && isset($current->next)) { + while ($current instanceof SinglyLinkedList && $current->next instanceof \SinglyLinkedList) { if ($current->next->data === $data) { $current->next = $current->next->next; return $this; diff --git a/DataStructures/SplayTree/SplayTree.php b/DataStructures/SplayTree/SplayTree.php index c14b64ab..b20a6619 100644 --- a/DataStructures/SplayTree/SplayTree.php +++ b/DataStructures/SplayTree/SplayTree.php @@ -1,5 +1,7 @@ root === null; + return !$this->root instanceof \DataStructures\SplayTree\SplayTreeNode; } /** @@ -77,7 +79,7 @@ public function isEmpty(): bool */ protected function splay(?SplayTreeNode $node, int $key): ?SplayTreeNode { - if ($node === null || $node->key === $key) { + if (!$node instanceof \DataStructures\SplayTree\SplayTreeNode || $node->key === $key) { return $node; } @@ -101,17 +103,20 @@ private function splayLeft(?SplayTreeNode $node, int $key): ?SplayTreeNode if ($node->left === null) { return $node; // Key not found in the left subtree } - - if ($node->left->key > $key) { // Zig-Zig (Left-Left case) + if ($node->left->key > $key) { + // Zig-Zig (Left-Left case) $node->left->left = $this->splay($node->left->left, $key); return $this->zigZig($node); - } elseif ($node->left->key < $key) { // Zig-Zag (Left-Right case) - $node->left->right = $this->splay($node->left->right, $key); + } - if ($node->left->right !== null) { + if ($node->left->key < $key) { + // Zig-Zag (Left-Right case) + $node->left->right = $this->splay($node->left->right, $key); + if ($node->left->right instanceof \DataStructures\SplayTree\SplayTreeNode) { return $this->zigZag($node); } } + // Zig (Left case) return $node->left === null ? $node @@ -133,15 +138,16 @@ private function splayRight(?SplayTreeNode $node, int $key): ?SplayTreeNode if ($node->right === null) { return $node; } - - if ($node->right->key < $key) { // Zag-Zag (Right-Right case) + if ($node->right->key < $key) { + // Zag-Zag (Right-Right case) $node->right->right = $this->splay($node->right->right, $key); - return $this->zagZag($node); - } elseif ($node->right->key > $key) { // Zag-Zig (Right-Left case) - $node->right->left = $this->splay($node->right->left, $key); + } - if ($node->right->left !== null) { + if ($node->right->key > $key) { + // Zag-Zig (Right-Left case) + $node->right->left = $this->splay($node->right->left, $key); + if ($node->right->left instanceof \DataStructures\SplayTree\SplayTreeNode) { return $this->zagZig($node); } } @@ -163,7 +169,7 @@ private function splayRight(?SplayTreeNode $node, int $key): ?SplayTreeNode * @return SplayTreeNode|null Returns the new root after insertion and splaying * @throws LogicException If the key already exists */ - public function insert(int $key, $value): ?SplayTreeNode + public function insert(int $key, mixed $value): ?SplayTreeNode { $this->root = $this->insertNode($this->root, $key, $value); $this->counter++; @@ -183,9 +189,9 @@ public function insert(int $key, $value): ?SplayTreeNode * @return SplayTreeNode|null Returns the new root after insertion * @throws LogicException If the key already exists */ - private function insertNode(?SplayTreeNode $node, int $key, $value): SplayTreeNode + private function insertNode(?SplayTreeNode $node, int $key, mixed $value): SplayTreeNode { - if ($node === null) { + if (!$node instanceof \DataStructures\SplayTree\SplayTreeNode) { return new SplayTreeNode($key, $value); } @@ -223,7 +229,7 @@ public function search(int $key): ?SplayTreeNode $node = $this->searchNode($this->root, $key, $lastVisited); - $this->root = $node !== null + $this->root = $node instanceof \DataStructures\SplayTree\SplayTreeNode ? $this->splay($this->root, $key) : $this->splay($this->root, $lastVisited->key); @@ -242,15 +248,16 @@ public function search(int $key): ?SplayTreeNode */ private function searchNode(?SplayTreeNode $node, int $key, ?SplayTreeNode &$lastVisited): ?SplayTreeNode { - if ($node === null) { + if (!$node instanceof \DataStructures\SplayTree\SplayTreeNode) { return null; } $lastVisited = $node; - if ($key < $node->key) { return $this->searchNode($node->left, $key, $lastVisited); - } elseif ($key > $node->key) { + } + + if ($key > $node->key) { return $this->searchNode($node->right, $key, $lastVisited); } else { return $node; @@ -269,7 +276,7 @@ private function searchNode(?SplayTreeNode $node, int $key, ?SplayTreeNode &$las public function isFound(int $key): bool { $foundNode = $this->search($key); - return $foundNode && $foundNode->key === $key; + return $foundNode instanceof \DataStructures\SplayTree\SplayTreeNode && $foundNode->key === $key; } /** @@ -283,11 +290,12 @@ public function isFound(int $key): bool * @param mixed $value The new value to set * @return SplayTreeNode|null Returns the root of the tree after the update or the last visited */ - public function update(int $key, $value): ?SplayTreeNode + public function update(int $key, mixed $value): ?SplayTreeNode { if ($this->isFound($key)) { $this->root->value = $value; } + return $this->root; } @@ -324,6 +332,7 @@ private function isolateRoot(): void if ($this->root->left !== null) { $this->root->left->parent = null; } + if ($this->root->right !== null) { $this->root->right->parent = null; } @@ -339,7 +348,7 @@ private function isolateRoot(): void */ private function restructureAfterDeletion(?SplayTreeNode $leftSubtree, ?SplayTreeNode $rightSubtree): ?SplayTreeNode { - if ($leftSubtree === null) { + if (!$leftSubtree instanceof \DataStructures\SplayTree\SplayTreeNode) { return $this->handleEmptyLeftSubtree($rightSubtree); } @@ -355,9 +364,10 @@ private function restructureAfterDeletion(?SplayTreeNode $leftSubtree, ?SplayTre private function handleEmptyLeftSubtree(?SplayTreeNode $rightSubtreeRoot): ?SplayTreeNode { $this->root = $rightSubtreeRoot; - if ($this->root !== null) { + if ($this->root instanceof \DataStructures\SplayTree\SplayTreeNode) { $this->root->parent = null; } + return $this->root; } @@ -388,11 +398,12 @@ private function mergeSubtrees(SplayTreeNode $leftSubtreeRoot, ?SplayTreeNode $r private function detachMaxNodeFromLeftSubtree(SplayTreeNode $maxLeftNode, SplayTreeNode $leftSubtreeRoot): void { $maxLeftNodeParent = $maxLeftNode->parent; - if ($maxLeftNodeParent !== null) { + if ($maxLeftNodeParent instanceof \DataStructures\SplayTree\SplayTreeNode) { $maxLeftNodeParent->right = null; $this->root->left = $leftSubtreeRoot; $leftSubtreeRoot->parent = $this->root; } + $maxLeftNode->parent = null; } @@ -404,7 +415,7 @@ private function detachMaxNodeFromLeftSubtree(SplayTreeNode $maxLeftNode, SplayT private function attachRightSubtree(?SplayTreeNode $rightSubtreeRoot): void { $this->root->right = $rightSubtreeRoot; - if ($rightSubtreeRoot !== null) { + if ($rightSubtreeRoot instanceof \DataStructures\SplayTree\SplayTreeNode) { $rightSubtreeRoot->parent = $this->root; } } @@ -419,12 +430,13 @@ private function attachRightSubtree(?SplayTreeNode $rightSubtreeRoot): void */ public function maxNode(?SplayTreeNode $node): ?SplayTreeNode { - if ($node === null) { + if (!$node instanceof \DataStructures\SplayTree\SplayTreeNode) { return null; } - return $node->right === null - ? $node - : $this->maxNode($node->right); + + return $node->right instanceof \DataStructures\SplayTree\SplayTreeNode + ? $this->maxNode($node->right) + : $node; } /** @@ -436,11 +448,12 @@ public function maxNode(?SplayTreeNode $node): ?SplayTreeNode public function inOrderTraversal(?SplayTreeNode $node): array { $result = []; - if ($node !== null) { + if ($node instanceof \DataStructures\SplayTree\SplayTreeNode) { $result = array_merge($result, $this->inOrderTraversal($node->left)); $result[] = [$node->key => $node->value]; $result = array_merge($result, $this->inOrderTraversal($node->right)); } + return $result; } } diff --git a/DataStructures/SplayTree/SplayTreeNode.php b/DataStructures/SplayTree/SplayTreeNode.php index a11df33d..f140b9e4 100644 --- a/DataStructures/SplayTree/SplayTreeNode.php +++ b/DataStructures/SplayTree/SplayTreeNode.php @@ -1,5 +1,7 @@ key = $key; - $this->value = $value; - - // Set all node pointers to null initially - $this->left = null; - $this->right = null; - $this->parent = null; } public function isLeaf(): bool { - return $this->left === null && $this->right === null; + return !$this->left instanceof \DataStructures\SplayTree\SplayTreeNode && !$this->right instanceof \DataStructures\SplayTree\SplayTreeNode; } public function isRoot(): bool { - return $this->parent === null; + return !$this->parent instanceof \DataStructures\SplayTree\SplayTreeNode; } } diff --git a/DataStructures/SplayTree/SplayTreeRotations.php b/DataStructures/SplayTree/SplayTreeRotations.php index 3375caa1..3a17809d 100644 --- a/DataStructures/SplayTree/SplayTreeRotations.php +++ b/DataStructures/SplayTree/SplayTreeRotations.php @@ -1,5 +1,7 @@ right; - if ($rightChild === null) { + if (!$rightChild instanceof \DataStructures\SplayTree\SplayTreeNode) { return $node; // No rotation possible } $node->right = $rightChild->left; - if ($rightChild->left !== null) { + if ($rightChild->left instanceof \DataStructures\SplayTree\SplayTreeNode) { $rightChild->left->parent = $node; } $rightChild->parent = $node->parent; - if ($node->parent === null) { + if (!$node->parent instanceof \DataStructures\SplayTree\SplayTreeNode) { static::setRoot($rightChild); } elseif ($node === $node->parent->left) { $node->parent->left = $rightChild; @@ -147,19 +150,19 @@ private function rotateRight(SplayTreeNode $node): SplayTreeNode { $leftChild = $node->left; - if ($leftChild === null) { + if (!$leftChild instanceof \DataStructures\SplayTree\SplayTreeNode) { return $node; // No rotation possible } $node->left = $leftChild->right; - if ($leftChild->right !== null) { + if ($leftChild->right instanceof \DataStructures\SplayTree\SplayTreeNode) { $leftChild->right->parent = $node; } $leftChild->parent = $node->parent; - if ($node->parent === null) { + if (!$node->parent instanceof \DataStructures\SplayTree\SplayTreeNode) { static::setRoot($leftChild); } elseif ($node === $node->parent->right) { $node->parent->right = $leftChild; diff --git a/DataStructures/Stack.php b/DataStructures/Stack.php index eaeb7c58..4762abd1 100644 --- a/DataStructures/Stack.php +++ b/DataStructures/Stack.php @@ -1,15 +1,14 @@ stack = $array; } public function __destruct() @@ -20,10 +19,10 @@ public function __destruct() public function push($data): void { - array_push($this->stack, $data); + $this->stack[] = $data; } - public function pop() + public function pop(): mixed { return array_pop($this->stack); } @@ -35,7 +34,7 @@ public function peek() public function isEmpty(): bool { - return empty($this->stack); + return $this->stack === []; } public function print(): void @@ -60,7 +59,7 @@ public function clear(): void public function search($data): int { - return array_search($data, $this->stack); + return array_search($data, $this->stack, true); } public function toArray(): array diff --git a/DataStructures/Trie/Trie.php b/DataStructures/Trie/Trie.php index 03b353a0..e2ba9ef9 100644 --- a/DataStructures/Trie/Trie.php +++ b/DataStructures/Trie/Trie.php @@ -1,5 +1,7 @@ addChild($char); } + $node->isEndOfWord = true; } @@ -52,8 +55,10 @@ public function search(string $word): bool if (!$node->hasChild($char)) { return false; } + $node = $node->getChild($char); } + return $node->isEndOfWord; } @@ -69,8 +74,10 @@ public function startsWith(string $prefix): array if (!$node->hasChild($char)) { return []; } + $node = $node->getChild($char); } + return $this->findWordsFromNode($node, $prefix); } @@ -118,13 +125,14 @@ private function deleteHelper(TrieNode $node, string &$word, int $index): bool if (!$node->isEndOfWord) { return false; } + $node->isEndOfWord = false; - return empty($node->children); + return $node->children === []; } $char = $word[$index]; $childNode = $node->getChild($char); - if ($childNode === null) { + if (!$childNode instanceof \DataStructures\Trie\TrieNode) { return false; } diff --git a/DataStructures/Trie/TrieNode.php b/DataStructures/Trie/TrieNode.php index 303da902..d3299db2 100644 --- a/DataStructures/Trie/TrieNode.php +++ b/DataStructures/Trie/TrieNode.php @@ -1,5 +1,7 @@ */ - public array $children; - public bool $isEndOfWord; + public array $children = []; - public function __construct() - { - $this->children = []; // Associative array where [ char => TrieNode ] - $this->isEndOfWord = false; - } + public bool $isEndOfWord = false; /** * Add a child node for a character. @@ -32,6 +29,7 @@ public function addChild(string $char): TrieNode if (!isset($this->children[$char])) { $this->children[$char] = new TrieNode(); } + return $this->children[$char]; } diff --git a/Graphs/BellmanFord.php b/Graphs/BellmanFord.php index 7173e6ea..154fe7c8 100644 --- a/Graphs/BellmanFord.php +++ b/Graphs/BellmanFord.php @@ -1,5 +1,7 @@ $minWeight) { + foreach (array_keys($vertices) as $vertice) { if ($verbose) { - echo "checking vertex $vertice\n"; + echo sprintf('checking vertex %s%s', $vertice, PHP_EOL); } + if ($start === $vertice) { $vertices[$vertice] = 0; } @@ -33,15 +37,18 @@ function bellmanFord(array $verticesNames, array $edges, string $start, bool $ve foreach ($edges[$vertice] as $edge) { if ($vertices[$edge->end] > $vertices[$vertice] + $edge->weight) { if ($verbose) { - echo "replace $vertice " . $vertices[$edge->end] . " with " + echo sprintf('replace %s ', $vertice) . $vertices[$edge->end] . " with " . ($vertices[$vertice] + $edge->weight) . "\n "; } + $vertices[$edge->end] = $vertices[$vertice] + $edge->weight; $change = true; } } } + $round++; } + return $vertices; } diff --git a/Graphs/BreadthFirstSearch.php b/Graphs/BreadthFirstSearch.php index 205e7f14..fcbdbb49 100644 --- a/Graphs/BreadthFirstSearch.php +++ b/Graphs/BreadthFirstSearch.php @@ -1,5 +1,7 @@ $weight) { - if (in_array($name, $visitedNodes) || $name == $nextVertex) { + if (in_array($name, $visitedNodes)) { + continue; + } + if ($name == $nextVertex) { continue; } if ($weight <= $minVertexWeight) { @@ -36,8 +41,10 @@ function dijkstras(array $verticesNames, array $edges, string $start): array $minVertexWeight = $weight; } } + $visitedNodes[] = $nextVertex; $nextVertex = $minVertexName; } + return $vertices; } diff --git a/Graphs/GraphEdge.php b/Graphs/GraphEdge.php index df73f082..25ad5d33 100644 --- a/Graphs/GraphEdge.php +++ b/Graphs/GraphEdge.php @@ -1,8 +1,12 @@ $absoluteMax) { $absoluteMax = $numbers[$loopIndex]; } diff --git a/Maths/AbsoluteMin.php b/Maths/AbsoluteMin.php index 36398689..dfa2ecc0 100644 --- a/Maths/AbsoluteMin.php +++ b/Maths/AbsoluteMin.php @@ -1,5 +1,7 @@ 0 && $set->valid()) { diff --git a/Maths/GreatestCommonDivisor.php b/Maths/GreatestCommonDivisor.php index 54758359..af2a51ba 100644 --- a/Maths/GreatestCommonDivisor.php +++ b/Maths/GreatestCommonDivisor.php @@ -1,16 +1,16 @@ 6 - * @param int $a - * @param int $b - * @return int */ function gcd(int $a, int $b): int { if ($b == 0) { return $a; } + return gcd($b, $a % $b); } diff --git a/Maths/Mean.php b/Maths/Mean.php index b24b4e01..2958a9da 100644 --- a/Maths/Mean.php +++ b/Maths/Mean.php @@ -1,5 +1,7 @@ 2 && $row < $matrix_size - 3) { $product = diagonalLeftProduct($grid_matrix, $row, $col); diff --git a/Maths/ProjectEuler/Problem2.php b/Maths/ProjectEuler/Problem2.php index c8ae460b..afb31097 100644 --- a/Maths/ProjectEuler/Problem2.php +++ b/Maths/ProjectEuler/Problem2.php @@ -1,28 +1,7 @@ $largest) { + if (strrev((string)$product) === (string)$product && $product > $largest) { $largest = $product; } } diff --git a/Maths/ProjectEuler/Problem5.php b/Maths/ProjectEuler/Problem5.php index 55608d2d..f615e97e 100644 --- a/Maths/ProjectEuler/Problem5.php +++ b/Maths/ProjectEuler/Problem5.php @@ -1,16 +1,7 @@ initParams(count($X)); @@ -36,23 +31,17 @@ public function trainModel(array $X, array $Y, int $iterations, float $learningR [$W, $b] = $this->updateParams($W, $b, $dW, $db, $learningRate); if ($i % 100 == 0) { - echo "Iteration {$i} - Cost: {$cost}\n"; + echo sprintf('Iteration %d - Cost: %s%s', $i, $cost, PHP_EOL); } } return [$W, $b]; } - /** - * @param array $X - * @param array $W - * @param float $b - * @return array - */ public function predict(array $X, array $W, float $b): array { $A = $this->forwardPropagation($X, $W, $b); - return array_map(fn($a) => $a > 0.5 ? 1 : 0, $A); + return array_map(fn ($a): int => $a > 0.5 ? 1 : 0, $A); } /** @@ -67,7 +56,7 @@ public function generateTrainingSet(): array $X = []; for ($i = 0; $i < 2; $i++) { for ($j = 0; $j < $m; $j++) { - $X[$i][$j] = rand(0, 1); + $X[$i][$j] = random_int(0, 1); } } @@ -80,25 +69,24 @@ public function generateTrainingSet(): array return [$X, $Y]; } - /** - * Stage 2. Initialize model parameters - * @param int $n Number of features - * @return array [$W, $b] Weight and bias arrays - */ + /** + * Stage 2. Initialize model parameters + * @param int $n Number of features + * @return array [$W, $b] Weight and bias arrays + */ private function initParams(int $n): array { $W = []; for ($i = 0; $i < $n; $i++) { $W[$i] = mt_rand() / mt_getrandmax(); // Small random values } + $b = 0.0; // Bias initialized to zero return [$W, $b]; } /** * Sigmoid Activation Function - * @param float $z - * @return float */ private function sigmoid(float $z): float { @@ -107,29 +95,25 @@ private function sigmoid(float $z): float /** * Stage 3. Forward Propagation - * @param array $X - * @param array $W - * @param float $b - * @return array */ private function forwardPropagation(array $X, array $W, float $b): array { $Z = []; - for ($j = 0; $j < count($X[0]); $j++) { + $counter = count($X[0]); + for ($j = 0; $j < $counter; $j++) { $sum = $b; for ($i = 0; $i < count($W); $i++) { $sum += $W[$i] * $X[$i][$j]; } + $Z[$j] = $this->sigmoid($sum); } + return $Z; } /** * Stage 4. Compute Cost Function (Binary Cross-Entropy Loss) - * @param array $A - * @param array $Y - * @return float */ private function computeCost(array $A, array $Y): float { @@ -138,15 +122,12 @@ private function computeCost(array $A, array $Y): float for ($i = 0; $i < $m; $i++) { $cost += -($Y[$i] * log($A[$i]) + (1 - $Y[$i]) * log(1 - $A[$i])); } + return $cost / $m; } /** * Stage 5. Backward Propagation - * @param array $A - * @param array $X - * @param array $Y - * @return array */ private function backwardPropagation(array $A, array $X, array $Y): array { @@ -156,16 +137,22 @@ private function backwardPropagation(array $A, array $X, array $Y): array for ($j = 0; $j < $m; $j++) { $dZ = $A[$j] - $Y[$j]; - for ($i = 0; $i < count($X); $i++) { + $counter = count($X); + for ($i = 0; $i < $counter; $i++) { $dW[$i] += $dZ * $X[$i][$j]; } + $db += $dZ; } // Average gradients - for ($i = 0; $i < count($dW); $i++) { + $counter = count($dW); + + // Average gradients + for ($i = 0; $i < $counter; $i++) { $dW[$i] /= $m; } + $db /= $m; return [$dW, $db]; @@ -173,18 +160,14 @@ private function backwardPropagation(array $A, array $X, array $Y): array /** * STage 6. Update Parameters - * @param array $W - * @param float $b - * @param array $dW - * @param float $db - * @param float $learningRate - * @return array */ private function updateParams(array $W, float $b, array $dW, float $db, float $learningRate): array { - for ($i = 0; $i < count($W); $i++) { + $counter = count($W); + for ($i = 0; $i < $counter; $i++) { $W[$i] -= $learningRate * $dW[$i]; } + $b -= $learningRate * $db; return [$W, $b]; diff --git a/Searches/BinarySearch.php b/Searches/BinarySearch.php index 10789307..bf30b93a 100644 --- a/Searches/BinarySearch.php +++ b/Searches/BinarySearch.php @@ -1,5 +1,7 @@ > 1; - - if ($list[$mid] == $target) { return $mid; - } elseif ($list[$mid] > $target) { + } + + + if ($list[$mid] > $target) { $last = $mid - 1; } elseif ($list[$mid] < $target) { $first = $mid + 1; @@ -60,7 +62,7 @@ function binarySearchIterative($list, $target) * @param integer $end an integer number where to end searching in the list * @return integer the index where the target is found (or null if not found) */ -function binarySearchByRecursion($list, $target, $start, $end) +function binarySearchByRecursion(array $list, $target, $start, $end) { if (count($list) == 0) { return null; @@ -76,13 +78,15 @@ function binarySearchByRecursion($list, $target, $start, $end) $mid = ($start + $end) >> 1; - - if ($list[$mid] == $target) { return $mid; - } elseif ($list[$mid] > $target) { + } + if ($list[$mid] > $target) { return binarySearchByRecursion($list, $target, $start, $mid - 1); - } elseif ($list[$mid] < $target) { + } + + + if ($list[$mid] < $target) { return binarySearchByRecursion($list, $target, $mid + 1, $end); } diff --git a/Searches/ExponentialSearch.php b/Searches/ExponentialSearch.php index 1ea8a1c9..5393f7a0 100644 --- a/Searches/ExponentialSearch.php +++ b/Searches/ExponentialSearch.php @@ -1,5 +1,7 @@ $value) { return binarySearch($arr, $value, $floor, $mid - 1); - } else { // search the right part of the $array If the $middle element is lower than the $value - return binarySearch($arr, $value, $mid + 1, $ceiling); } + // search the right part of the $array If the $middle element is lower than the $value + return binarySearch($arr, $value, $mid + 1, $ceiling); } /** - * @param Array $arr * @param int $value * @return int */ -function exponentialSearch($arr, $value) +function exponentialSearch(array $arr, $value) { // If $value is the first element of the $array return this position if ($arr[0] === $value) { @@ -56,8 +55,9 @@ function exponentialSearch($arr, $value) $i = 1; $length = count($arr); while ($i < $length && $arr[$i] <= $value) { - $i = $i * 2; + $i *= 2; } + $floor = $i / 2; $ceiling = min($i, $length); diff --git a/Searches/FibonacciSearch.php b/Searches/FibonacciSearch.php index b103785a..08eacd45 100644 --- a/Searches/FibonacciSearch.php +++ b/Searches/FibonacciSearch.php @@ -1,5 +1,7 @@ key decrease the high index * repeat the loop */ -function interpolationSearch($arr, $key) +function interpolationSearch(array $arr, $key): ?int { $length = count($arr) - 1; $low = 0; @@ -30,14 +32,15 @@ function interpolationSearch($arr, $key) //GET VALUE OF INDEX IN ARRAY... $indexValue = $arr[$index]; - if ($indexValue === $key) { //index value equals key //FOUND TARGET //return index value $position = $index; return (int) $position; - } elseif ($indexValue < $key) { + } + + if ($indexValue < $key) { //index value lower than key //increase low index $low = $index + 1; diff --git a/Searches/JumpSearch.php b/Searches/JumpSearch.php index a84daa7e..1a83f732 100644 --- a/Searches/JumpSearch.php +++ b/Searches/JumpSearch.php @@ -1,5 +1,7 @@ $arr[$mid2]) { + } + + // Determine which section to continue searching in. + if ($key > $arr[$mid2]) { // Key is in the right section, between $mid2 and $high. return ternarySearchByRecursion($arr, $key, $mid2 + 1, $high); } else { // Key is in the middle section, between $mid1 and $mid2. return ternarySearchByRecursion($arr, $key, $mid1 + 1, $mid2 - 1); } + return null; } -function ternarySearchIterative($arr, $key) +function ternarySearchIterative(array $arr, $key): ?float { // Initialize low and high pointers. $low = 0; diff --git a/Searches/TwoPointers.php b/Searches/TwoPointers.php index f05e5daa..57e5ee79 100644 --- a/Searches/TwoPointers.php +++ b/Searches/TwoPointers.php @@ -1,5 +1,7 @@ $target) { + } elseif ($list[$left] + $list[$right] > $target) { // the sum is greater than the target, so we need to decrease the sum // to decrease the sum we will move our $right pointer to the left $right--; - } else if ($list[$left] + $list[$right] == $target) { + } elseif ($list[$left] + $list[$right] == $target) { // if it's true, we have found a pair $ans++; // now we will move one of our pointers, otherwise it'll run forever - $left++; # doesn't matter which one we move + $left++; + # doesn't matter which one we move } + // The loop will go until the pointers point to the same element } + return $ans; # returning the number of pairs } diff --git a/Searches/UpperBound.php b/Searches/UpperBound.php index 47d62518..f9aebff8 100644 --- a/Searches/UpperBound.php +++ b/Searches/UpperBound.php @@ -1,5 +1,7 @@ $key) || !isset($b->$key)) { $errorMsg = 'The key "' . $key . '" does not exist in the collection'; throw new Exception($errorMsg); } - $item1 = !$isCaseSensitive - ? strtolower($a->$key) : $a->$key; - $item2 = !$isCaseSensitive - ? strtolower($b->$key) : $b->$key; + + $item1 = $isCaseSensitive + ? $a->$key : strtolower((string) $a->$key); + $item2 = $isCaseSensitive + ? $b->$key : strtolower((string) $b->$key); } } while ($item1 === $item2 && !empty($keys[++$pos])); if ($item1 === $item2) { return 0; - } elseif ($order === self::ORDER_ASC) { + } + + if ($order === self::ORDER_ASC) { return ($item1 < $item2) ? -1 : 1; } else { return ($item1 > $item2) ? -1 : 1; diff --git a/Sorting/BubbleSort.php b/Sorting/BubbleSort.php index 9bc66795..7de84d68 100644 --- a/Sorting/BubbleSort.php +++ b/Sorting/BubbleSort.php @@ -1,12 +1,11 @@ = 0; $i--) { + for ($i = (int) ($n / 2) - 1; $i >= 0; $i--) { heapify($arr, $n, $i); } @@ -41,10 +41,6 @@ function heapSort(array $arr): array /** * Ensures that the array satisfies the heap property - * - * @param array $arr - * @param int $n - * @param int $i */ function heapify(array &$arr, int $n, int $i): void { diff --git a/Sorting/InsertionSort.php b/Sorting/InsertionSort.php index fcffaa00..57e3142c 100644 --- a/Sorting/InsertionSort.php +++ b/Sorting/InsertionSort.php @@ -1,14 +1,14 @@ = 0 && $array[$j] > $currentVal; $j--) { diff --git a/Sorting/MergeSort.php b/Sorting/MergeSort.php index 23c64178..cc92d006 100644 --- a/Sorting/MergeSort.php +++ b/Sorting/MergeSort.php @@ -1,9 +1,10 @@ createNode`) to satisfy PHPUnit 10+ data provider architecture rules. +* **`tests/Conversions/ConversionsTest.php` (Lines 17-143):** Updated assertion expected types to `\Throwable::class` to accurately trap the new engine-level `TypeError` exceptions natively thrown by PHP 8.2 strict engines instead of generic `Exception`. + +--- +*Authored to catalog the PHP ~8.2 framework transition.* diff --git a/Utils/ArrayHelpers.php b/Utils/ArrayHelpers.php index 37602e99..2385ee63 100644 --- a/Utils/ArrayHelpers.php +++ b/Utils/ArrayHelpers.php @@ -1,5 +1,7 @@ assertEquals(7, binaryToDecimal(111)); $this->assertEquals(5, binaryToDecimal(101)); - $this->expectException(\Exception::class); + $this->expectException(\Throwable::class); $this->expectExceptionMessage('Please pass a valid Binary Number for Converting it to a Decimal Number.'); binaryToDecimal("this is a string"); } @@ -26,7 +26,7 @@ public function testDecimalToBinary() { $this->assertEquals(111, decimalToBinary(7)); $this->assertEquals(101, decimalToBinary(5)); - $this->expectException(\Exception::class); + $this->expectException(\Throwable::class); $this->expectExceptionMessage('Please pass a valid Decimal Number for Converting it to a Binary Number.'); decimalToBinary("this is a string"); } @@ -36,7 +36,7 @@ public function testOctalToDecimal() $this->assertEquals(8, octalToDecimal(10)); $this->assertEquals(9, octalToDecimal(11)); $this->assertEquals(589, octalToDecimal(1115)); - $this->expectException(\Exception::class); + $this->expectException(\Throwable::class); $this->expectExceptionMessage('Please pass a valid Octal Number for Converting it to a Decimal Number.'); octalToDecimal("this is a string"); } @@ -46,7 +46,7 @@ public function testDecimalToOctal() $this->assertEquals(10, decimalToOctal(8)); $this->assertEquals(11, decimalToOctal(9)); $this->assertEquals(1115, decimalToOctal(589)); - $this->expectException(\Exception::class); + $this->expectException(\Throwable::class); $this->expectExceptionMessage('Please pass a valid Decimal Number for Converting it to an Octal Number.'); decimalToOctal("this is a string"); } @@ -56,7 +56,7 @@ public function testDecimalToHex() $this->assertEquals('A', decimalToHex(10)); $this->assertEquals('1D28A0D3', decimalToHex(489201875)); $this->assertEquals('AB', decimalToHex(171)); - $this->expectException(\Exception::class); + $this->expectException(\Throwable::class); $this->expectExceptionMessage('Please pass a valid Decimal Number for Converting it to a Hexadecimal Number.'); decimalToHex("this is a string"); } @@ -66,7 +66,7 @@ public function testHexToDecimal() $this->assertEquals(10, hexToDecimal('A')); $this->assertEquals(489201875, hexToDecimal('1D28A0D3')); $this->assertEquals(171, hexToDecimal('AB')); - $this->expectException(\Exception::class); + $this->expectException(\Throwable::class); $this->expectExceptionMessage('Please pass a valid Hexadecimal Number for Converting it to a Decimal Number.'); hexToDecimal("this is a string"); } @@ -74,13 +74,13 @@ public function testHexToDecimal() public function testSpeedConversion() { $this->assertEquals(11.18, convertSpeed(5, 'm/s', 'mph')); - $this->assertEquals(5.49, convertSpeed(5, 'ft/s', 'km/h')); + $this->assertEqualsWithDelta(5.485, convertSpeed(5, 'ft/s', 'km/h'), 0.01); $this->assertEquals(3, convertSpeed(3, 'km/h', 'km/h')); $this->assertEquals(12.96, convertSpeed(7, 'kn', 'km/h')); $this->assertEquals(19.31, convertSpeed(12, 'mph', 'km/h')); $this->assertEquals(1, convertSpeed(0.514, 'm/s', 'kn')); - $this->expectException(\Exception::class); + $this->expectException(\Throwable::class); convertSpeed('1', 'km/h', 'mph'); $this->expectException(\Exception::class); @@ -92,7 +92,7 @@ public function testCelsiusToFahrenheit() $this->assertEquals(32.0, CelsiusToFahrenheit(0)); $this->assertEquals(212.0, CelsiusToFahrenheit(100)); $this->assertEquals(98.6, CelsiusToFahrenheit(37)); - $this->expectException(\Exception::class); + $this->expectException(\Throwable::class); $this->expectExceptionMessage('Temperature (Celsius) must be a number'); CelsiusToFahrenheit("non-numeric"); } @@ -102,7 +102,7 @@ public function testFahrenheitToCelsius() $this->assertEquals(0.0, FahrenheitToCelsius(32)); $this->assertEquals(100.0, FahrenheitToCelsius(212)); $this->assertEquals(37.0, FahrenheitToCelsius(98.6)); - $this->expectException(\Exception::class); + $this->expectException(\Throwable::class); $this->expectExceptionMessage('Temperature (Fahrenheit) must be a number'); FahrenheitToCelsius("non-numeric"); } @@ -111,7 +111,7 @@ public function testCelsiusToKelvin() { $this->assertEquals(273.15, CelsiusToKelvin(0)); $this->assertEquals(373.15, CelsiusToKelvin(100)); - $this->expectException(\Exception::class); + $this->expectException(\Throwable::class); $this->expectExceptionMessage('Temperature (Celsius) must be a number'); CelsiusToKelvin("non-numeric"); } @@ -120,7 +120,7 @@ public function testKelvinToCelsius() { $this->assertEquals(0.0, KelvinToCelsius(273.15)); $this->assertEquals(100.0, KelvinToCelsius(373.15)); - $this->expectException(\Exception::class); + $this->expectException(\Throwable::class); $this->expectExceptionMessage('Temperature (Kelvin) must be a number'); KelvinToCelsius("non-numeric"); } @@ -129,7 +129,7 @@ public function testKelvinToFahrenheit() { $this->assertEquals(32.0, KelvinToFahrenheit(273.15)); $this->assertEquals(212.0, KelvinToFahrenheit(373.15)); - $this->expectException(\Exception::class); + $this->expectException(\Throwable::class); $this->expectExceptionMessage('Temperature (Kelvin) must be a number'); KelvinToFahrenheit("non-numeric"); } @@ -138,7 +138,7 @@ public function testFahrenheitToKelvin() { $this->assertEquals(273.15, FahrenheitToKelvin(32)); $this->assertEquals(373.15, FahrenheitToKelvin(212)); - $this->expectException(\Exception::class); + $this->expectException(\Throwable::class); $this->expectExceptionMessage('Temperature (Fahrenheit) must be a number'); FahrenheitToKelvin("non-numeric"); } diff --git a/tests/DataStructures/SinglyLinkedListTest.php b/tests/DataStructures/SinglyLinkedListTest.php index 39bdc5fe..18fa07e8 100644 --- a/tests/DataStructures/SinglyLinkedListTest.php +++ b/tests/DataStructures/SinglyLinkedListTest.php @@ -27,23 +27,23 @@ private function createNode(string $string): SinglyLinkedList /** * Provider of SinglyLinkedList nodes */ - public function provideNodes() + public static function provideNodes() { return [ 'IsPalindrome' => [ - 'node' => $this->createNode('hannah'), + 'string' => 'hannah', 'expected' => true ], 'IsPalindrome2' => [ - 'node' => $this->createNode('hanah'), + 'string' => 'hanah', 'expected' => true ], 'IsNotPalindrome' => [ - 'node' => $this->createNode('hanbah'), + 'string' => 'hanbah', 'expected' => false ], 'IsNotPalindrome2' => [ - 'node' => $this->createNode('han1h'), + 'string' => 'han1h', 'expected' => false ], ]; @@ -54,8 +54,9 @@ public function provideNodes() * * @dataProvider provideNodes */ - public function testIsPalindrome($node, $expected): void + public function testIsPalindrome($string, $expected): void { + $node = $this->createNode($string); $this->assertEquals($expected, $this->isPalindrome($node)); }