public static function areTreesEqual(BinaryTreeNode $tree1, BinaryTreeNode $tree2) { if ($tree1->getData() !== $tree2->getData()) { return false; } $queue1 = [$tree1]; $queue2 = [$tree2]; while (!empty($queue1)) { $node1 = array_shift($queue1); $node2 = array_shift($queue2); $pairs = [[$node1->getLeft(), $node2->getLeft()], [$node1->getRight(), $node2->getRight()]]; foreach ($pairs as $pair) { if ($pair[0] === null) { if ($pair[1] !== null) { return false; } } elseif ($pair[1] === null) { return false; } elseif ($pair[0]->getData() !== $pair[1]->getData()) { return false; } else { array_push($queue1, $pair[0]); array_push($queue2, $pair[1]); } } } return true; }
public function testGetDepths() { $firstLevel1 = new BinaryTreeNode("first level 1"); $secondLevel1 = new BinaryTreeNode("second level 1"); $secondLevel2 = new BinaryTreeNode("second level 2"); $thirdLevel1 = new BinaryTreeNode("third level 1"); $thirdLevel2 = new BinaryTreeNode("third level 2"); $thirdLevel3 = new BinaryTreeNode("third level 3"); $fourthLevel1 = new BinaryTreeNode("fourth level 1"); $firstLevel1->setLeft($secondLevel1); $firstLevel1->setRight($secondLevel2); $secondLevel1->setRight($thirdLevel1); $secondLevel2->setLeft($thirdLevel2); $secondLevel2->setRight($thirdLevel3); $thirdLevel2->setLeft($fourthLevel1); $firstLevel = new LinkedList(); $firstLevel->add($firstLevel1); $secondLevel = new LinkedList(); $secondLevel->add($secondLevel1); $secondLevel->add($secondLevel2); $thirdLevel = new LinkedList(); $thirdLevel->add($thirdLevel1); $thirdLevel->add($thirdLevel2); $thirdLevel->add($thirdLevel3); $fourthLevel = new LinkedList(); $fourthLevel->add($fourthLevel1); $expected = [$firstLevel, $secondLevel, $thirdLevel, $fourthLevel]; $this->assertEquals($expected, DFSDepthLister::getDepths($firstLevel1)); $this->assertEquals($expected, BFSDepthLister::getDepths($firstLevel1)); }
public function setRight(BinaryTreeNode $right = null) { $oldRight = $this->getRight(); $delta = ($oldRight !== null ? -$oldRight->getNodeCount() : 0) + ($right !== null ? $right->getNodeCount() : 0); parent::setRight($right); $this->updateNodeCount($delta); }
public static function getSequences(BinaryTreeNode $node) { $prefix = [$node->getData()]; $left = $node->getLeft(); $right = $node->getRight(); if ($left === null && $right === null) { return [$prefix]; } $leftSequences = $left !== null ? self::getSequences($left) : null; $rightSequences = $right !== null ? self::getSequences($right) : null; $sequences = []; if ($leftSequences === null) { foreach ($rightSequences as $rightSequence) { $sequences[] = array_merge($prefix, $rightSequence); } return $sequences; } if ($rightSequences === null) { foreach ($leftSequences as $leftSequence) { $sequences[] = array_merge($prefix, $leftSequence); } return $sequences; } // combine $leftSequences and $rightSequences in every possible way foreach ($leftSequences as $leftSequence) { foreach ($rightSequences as $rightSequence) { $mergedSequence = array_merge($leftSequence, $rightSequence); $orderings = self::getAllOrderings($mergedSequence); foreach ($orderings as $ordering) { $sequences[] = array_merge($prefix, $ordering); } } } return $sequences; }
public static function isBinarySearchTree(BinaryTreeNode $node, $min = null, $max = null) { $left = $node->getLeft(); $right = $node->getRight(); $nodeValue = $node->getData(); if ($left !== null) { $leftValue = $left->getData(); if ($nodeValue < $leftValue) { return false; } if ($min !== null && $min > $leftValue) { return false; } if (!self::isBinarySearchTree($left, $min, $nodeValue)) { return false; } } if ($right !== null) { $rightValue = $right->getData(); if ($nodeValue > $rightValue) { return false; } if ($max !== null && $max < $rightValue) { return false; } if (!self::isBinarySearchTree($right, $nodeValue, $max)) { return false; } } return true; }
public function testGetSequencesWithFiveNodes() { $n1 = new BinaryTreeNode(1); $n2 = new BinaryTreeNode(2); $n3 = new BinaryTreeNode(3); $n4 = new BinaryTreeNode(4); $n5 = new BinaryTreeNode(5); $n2->setLeft($n1); $n2->setRight($n3); $n3->setLeft($n4); $n4->setRight($n5); $expected = [[2, 1, 3, 4, 5], [2, 3, 1, 4, 5], [2, 3, 4, 1, 5], [2, 3, 4, 5, 1], [2, 1, 4, 3, 5], [2, 4, 1, 3, 5], [2, 4, 3, 1, 5], [2, 4, 3, 5, 1], [2, 1, 4, 5, 3], [2, 4, 1, 5, 3], [2, 4, 5, 1, 3], [2, 4, 5, 3, 1], [2, 1, 3, 5, 4], [2, 3, 1, 5, 4], [2, 3, 5, 1, 4], [2, 3, 5, 4, 1], [2, 1, 5, 3, 4], [2, 5, 1, 3, 4], [2, 5, 3, 1, 4], [2, 5, 3, 4, 1], [2, 1, 5, 4, 3], [2, 5, 1, 4, 3], [2, 5, 4, 1, 3], [2, 5, 4, 3, 1]]; $this->assertEquals($expected, BinarySearchTreeSequenceCalculator::getSequences($n2)); }
public static function countPathsWithSum(BinaryTreeNode $node, $targetSum, array $breadCrumb = []) { $newBreadCrumb = array_merge($breadCrumb, [$node->getData()]); $resultCount = self::getPathSumCount($newBreadCrumb, $targetSum); $left = $node->getLeft(); if ($left !== null) { $resultCount += self::countPathsWithSum($left, $targetSum, $newBreadCrumb); } $right = $node->getRight(); if ($right !== null) { $resultCount += self::countPathsWithSum($right, $targetSum, $newBreadCrumb); } return $resultCount; }
public static function build(array $a, $startIndex = 0, $endIndex = null) { if ($endIndex === null) { $endIndex = count($a) - 1; } $nodeIndex = self::getMidPoint($startIndex, $endIndex); $node = new BinaryTreeNode($a[$nodeIndex]); if ($nodeIndex - $startIndex > 0) { $node->setLeft(self::build($a, $startIndex, $nodeIndex - 1)); } if ($endIndex - $nodeIndex > 0) { $node->setRight(self::build($a, $nodeIndex + 1, $endIndex)); } return $node; }
public function testIsBinarySearchTree() { $n1 = new BinaryTreeNode(1); $n2 = new BinaryTreeNode(2); $n3 = new BinaryTreeNode(3); $n4 = new BinaryTreeNode(4); $n5 = new BinaryTreeNode(5); $n6 = new BinaryTreeNode(6); $n7 = new BinaryTreeNode(7); $n8 = new BinaryTreeNode(8); $n9 = new BinaryTreeNode(9); $n10 = new BinaryTreeNode(10); $n11 = new BinaryTreeNode(11); $n12 = new BinaryTreeNode(12); $n13 = new BinaryTreeNode(13); $n14 = new BinaryTreeNode(14); $n15 = new BinaryTreeNode(15); $n16 = new BinaryTreeNode(16); $n8->setLeft($n4); $n8->setRight($n12); $this->assertTrue(BinarySearchTreeChecker::isBinarySearchTree($n8)); $n4->setLeft($n2); $n4->setRight($n6); $this->assertTrue(BinarySearchTreeChecker::isBinarySearchTree($n8)); $n12->setLeft($n10); $n12->setRight($n14); $this->assertTrue(BinarySearchTreeChecker::isBinarySearchTree($n8)); $n2->setLeft($n16); $this->assertFalse(BinarySearchTreeChecker::isBinarySearchTree($n8)); $n2->setLeft($n1); $this->assertTrue(BinarySearchTreeChecker::isBinarySearchTree($n8)); $n2->setRight($n15); $this->assertFalse(BinarySearchTreeChecker::isBinarySearchTree($n8)); $n2->setRight($n3); $this->assertTrue(BinarySearchTreeChecker::isBinarySearchTree($n8)); $n10->setRight($n9); $this->assertFalse(BinarySearchTreeChecker::isBinarySearchTree($n8)); $n10->setRight($n11); $this->assertTrue(BinarySearchTreeChecker::isBinarySearchTree($n8)); $n14->setLeft($n5); $this->assertFalse(BinarySearchTreeChecker::isBinarySearchTree($n8)); $n14->setLeft($n13); $this->assertTrue(BinarySearchTreeChecker::isBinarySearchTree($n8)); $n6->setLeft($n5); $n6->setRight($n7); $this->assertTrue(BinarySearchTreeChecker::isBinarySearchTree($n8)); }
public function testBinaryTreeNode() { $node1 = new BinaryTreeNode('Dizzy'); $this->assertEquals('Dizzy', $node1->getData()); $this->assertEquals('Dizzy', (string) $node1); $node1->setData('Miles'); $this->assertEquals('Miles', $node1->getData()); $this->assertEquals('Miles', (string) $node1); $this->assertNull($node1->getLeft()); $this->assertNull($node1->getRight()); $node2 = new BinaryTreeNode('Cannonball'); $node3 = new BinaryTreeNode('Coltrane'); $node1->setLeft($node2); $node1->setRight($node3); $this->assertSame($node2, $node1->getLeft()); $this->assertSame($node3, $node1->getRight()); }
public static function countPathsWithSum(BinaryTreeNode $node = null, $targetSum, $runningSum = 0, array &$pathCountMap = []) { if ($node === null) { return 0; } $runningSum += $node->getData(); $sum = $runningSum - $targetSum; $totalPaths = array_key_exists($sum, $pathCountMap) ? $pathCountMap[$sum] : 0; if ($runningSum === $targetSum) { $totalPaths++; } $pathCountMap[$runningSum] = (array_key_exists($runningSum, $pathCountMap) ? $pathCountMap[$runningSum] : 0) + 1; $totalPaths += self::countPathsWithSum($node->getLeft(), $targetSum, $runningSum, $pathCountMap); $totalPaths += self::countPathsWithSum($node->getRight(), $targetSum, $runningSum, $pathCountMap); $pathCountMap[$runningSum] -= 1; return $totalPaths; }
public function setRight(BinaryTreeNode $right) { if (!$right instanceof BinaryTreeNodeWithParent) { throw new InvalidArgumentException('When building a binary tree with parent references, all nodes must be instances of BinaryTreeNodeWithParent'); } parent::setRight($right); $right->setParent($this); }
public function testIsBalanced() { $n1 = new BinaryTreeNode("one"); $n2 = new BinaryTreeNode("two"); $n3 = new BinaryTreeNode("three"); $n4 = new BinaryTreeNode("four"); $n5 = new BinaryTreeNode("five"); $n6 = new BinaryTreeNode("six"); $n7 = new BinaryTreeNode("seven"); $n8 = new BinaryTreeNode("eight"); $n9 = new BinaryTreeNode("nine"); $n10 = new BinaryTreeNode("ten"); $n11 = new BinaryTreeNode("eleven"); $n12 = new BinaryTreeNode("twelve"); $n13 = new BinaryTreeNode("thirteen"); $n14 = new BinaryTreeNode("fourteen"); $n15 = new BinaryTreeNode("fifteen"); $n16 = new BinaryTreeNode("sixteen"); $n1->setLeft($n2); $this->assertTrue(BalancedTreeChecker::isBalanced($n1)); $n1->setRight($n3); $this->assertTrue(BalancedTreeChecker::isBalanced($n1)); $n2->setLeft($n4); $this->assertTrue(BalancedTreeChecker::isBalanced($n1)); $n2->setRight($n5); $this->assertTrue(BalancedTreeChecker::isBalanced($n1)); $n3->setLeft($n6); $n3->setRight($n7); $this->assertTrue(BalancedTreeChecker::isBalanced($n1)); $n6->setLeft($n8); $n8->setLeft($n9); $this->assertFalse(BalancedTreeChecker::isBalanced($n1)); $n6->setRight($n10); $this->assertFalse(BalancedTreeChecker::isBalanced($n1)); $n10->setLeft($n11); $this->assertFalse(BalancedTreeChecker::isBalanced($n1)); $n4->setLeft($n12); $n4->setRight($n13); $this->assertFalse(BalancedTreeChecker::isBalanced($n1)); $n5->setLeft($n14); $n5->setRight($n15); $this->assertFalse(BalancedTreeChecker::isBalanced($n1)); $n7->setLeft($n16); $this->assertTrue(BalancedTreeChecker::isBalanced($n1)); }
public static function getMaxDepthOrNegativeOneIfUnbalanced(BinaryTreeNode $node = null) { if ($node === null) { return 0; } $leftDepth = self::getMaxDepthOrNegativeOneIfUnbalanced($node->getLeft()); if ($leftDepth == -1) { return -1; } $rightDepth = self::getMaxDepthOrNegativeOneIfUnbalanced($node->getRight()); if ($rightDepth == -1) { return -1; } if (abs($leftDepth - $rightDepth) > 1) { return -1; } return max($leftDepth, $rightDepth) + 1; }
protected static function findFirstCommonAncestorResult(BinaryTreeNode $node, BinaryTreeNode $p, BinaryTreeNode $q) { $isP = $node === $p; $isQ = $node === $q; $left = $node->getLeft(); $right = $node->getRight(); $leftIsP = false; $leftIsQ = false; $leftResult = null; if ($left !== null) { $leftResult = self::findFirstCommonAncestorResult($left, $p, $q); $leftReturnNode = $leftResult !== null ? $leftResult->getNode() : null; $leftIsP = $leftReturnNode === $p; $leftIsQ = $leftReturnNode === $q; if ($isP && $leftIsQ || $isQ && $leftIsP) { return new CommonAncestorResult($node, 2); } } $rightIsP = false; $rightIsQ = false; $rightResult = null; if ($right !== null) { $rightResult = self::findFirstCommonAncestorResult($right, $p, $q); $rightReturnNode = $rightResult !== null ? $rightResult->getNode() : null; $rightIsP = $rightReturnNode === $p; $rightIsQ = $rightReturnNode === $q; if ($isP && $rightIsQ || $isQ && $rightIsP) { return new CommonAncestorResult($node, 2); } } if ($leftIsP && $rightIsQ || $leftIsQ && $rightIsP) { return new CommonAncestorResult($node, 2); } if ($leftResult !== null) { return $leftResult; } elseif ($rightResult !== null) { return $rightResult; } elseif ($isP || $isQ) { $coverCount = ($isP ? 1 : 0) + ($isQ ? 1 : 0); return new CommonAncestorResult($node, $coverCount); } return null; }
public function testCountPathsMoreInterestingExample() { $n1 = new BinaryTreeNode(7); $n2 = new BinaryTreeNode(-2); $n3 = new BinaryTreeNode(4); $n4 = new BinaryTreeNode(1); $n5 = new BinaryTreeNode(-3); $n6 = new BinaryTreeNode(2); $n7 = new BinaryTreeNode(2); $n8 = new BinaryTreeNode(5); $n4->setLeft($n2); $n4->setRight($n6); $n2->setLeft($n1); $n2->setRight($n3); $n6->setLeft($n5); $n6->setRight($n7); $n5->setRight($n8); $this->assertEquals(4, PathsWithSumCounterBruteForce::countPathsWithSum($n4, 5)); $this->assertEquals(4, PathsWithSumCounter::countPathsWithSum($n4, 5)); }
public function testFindFirstCommonAncestorWithFourLevelTree() { $n1 = new BinaryTreeNode(1); $n2 = new BinaryTreeNode(2); $n3 = new BinaryTreeNode(3); $n4 = new BinaryTreeNode(4); $n5 = new BinaryTreeNode(5); $n6 = new BinaryTreeNode(6); $n7 = new BinaryTreeNode(7); $n8 = new BinaryTreeNode(8); $n9 = new BinaryTreeNode(9); $n10 = new BinaryTreeNode(10); $n11 = new BinaryTreeNode(11); $n12 = new BinaryTreeNode(12); $n13 = new BinaryTreeNode(13); $n14 = new BinaryTreeNode(14); $n15 = new BinaryTreeNode(15); $n8->setLeft($n4); $n8->setRight($n12); $n4->setLeft($n2); $n4->setRight($n6); $n12->setLeft($n10); $n12->setRight($n14); $n2->setLeft($n1); $n2->setRight($n3); $n6->setLeft($n5); $n6->setRight($n7); $n10->setLeft($n9); $n10->setRight($n11); $n14->setLeft($n13); $n14->setRight($n15); $this->assertSame($n8, FirstCommonAncestorFinder::findFirstCommonAncestor($n8, $n1, $n15)); $this->assertSame($n8, FirstCommonAncestorFinder::findFirstCommonAncestor($n8, $n4, $n12)); $this->assertSame($n4, FirstCommonAncestorFinder::findFirstCommonAncestor($n8, $n2, $n5)); $this->assertSame($n4, FirstCommonAncestorFinder::findFirstCommonAncestor($n8, $n6, $n1)); $this->assertSame($n4, FirstCommonAncestorFinder::findFirstCommonAncestor($n8, $n1, $n6)); $this->assertSame($n4, FirstCommonAncestorFinder::findFirstCommonAncestor($n8, $n1, $n4)); $this->assertSame($n6, FirstCommonAncestorFinder::findFirstCommonAncestor($n8, $n6, $n7)); }
public function testIsSubTree() { $t1n1 = new BinaryTreeNode(1); $t1n2 = new BinaryTreeNode(2); $t1n3 = new BinaryTreeNode(3); $t1n4 = new BinaryTreeNode(5); $t1n5 = new BinaryTreeNode(6); $t1n1->setLeft($t1n2); $t1n1->setRight($t1n3); $t1n3->setLeft($t1n4); $t1n3->setRight($t1n5); $t2n1 = new BinaryTreeNode(3); $t2n2 = new BinaryTreeNode(5); $t2n3 = new BinaryTreeNode(6); $t2n1->setLeft($t2n2); $t2n1->setRight($t2n3); $this->assertTrue(SubTreeChecker::isSubTree($t1n1, $t2n1)); $this->assertTrue(SubTreeChecker::isSubTree($t1n1, $t1n1)); $t3n1 = new BinaryTreeNode(3); $t3n2 = new BinaryTreeNode(4); $t3n1->setLeft($t3n2); $this->assertFalse(SubTreeChecker::isSubTree($t1n1, $t3n1)); $t3n3 = new BinaryTreeNode(5); $t3n1->setRight($t3n3); $this->assertFalse(SubTreeChecker::isSubTree($t1n1, $t3n1)); $t4n1 = new BinaryTreeNode(10); $t4n2 = new BinaryTreeNode(11); $t4n1->setLeft($t4n2); $this->assertFalse(SubTreeChecker::isSubTree($t1n1, $t4n1)); $t5n1 = new BinaryTreeNode(3); $t5n2 = new BinaryTreeNode(5); $t5n1->setLeft($t5n2); $this->assertFalse(SubTreeChecker::isSubTree($t1n1, $t5n1)); $t5n3 = new BinaryTreeNode(6); $t5n4 = new BinaryTreeNode(7); $t5n1->setRight($t5n3); $t5n2->setLeft($t5n4); $this->assertFalse(SubTreeChecker::isSubTree($t1n1, $t5n1)); }
public function setRight(BinaryTreeNode $right = null) { if ($right !== null && !$right instanceof BinaryTreeNodeWithParent) { throw new InvalidArgumentException('When building a binary tree with parent references, all nodes must be instances of BinaryTreeNodeWithParent'); } $oldRight = $this->getRight(); if ($oldRight !== null) { $oldRight->setParent(null); } parent::setRight($right); if ($right !== null) { $right->setParent($this); } }