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);
     }
 }