Tree

作者: 瞬铭 | 来源:发表于2017-10-17 21:06 被阅读0次

    生成tree

     <?php
     $arr = array(
         array('id' => 1, 'pid' => -1, 'name' => 'test1', ),
         array('id' => 2, 'pid' => -1, 'name' => 'test2', ),
         array('id' => 3, 'pid' => -1, 'name' => 'test3', ),
         array('id' => 4, 'pid' => -1, 'name' => 'test4', ),
         array('id' => 5, 'pid' =>  1, 'name' => 'test5', ),
         array('id' => 6, 'pid' =>  2, 'name' => 'test6', ),
         array('id' => 7, 'pid' =>  3, 'name' => 'test7', ),
         array('id' => 8, 'pid' =>  4, 'name' => 'test8', ),
         array('id' => 9, 'pid' =>  7, 'name' => 'test9', ),
         array('id' => 10, 'pid' => -1, 'name' => 'test10', ),
     );
     $maps = array();
     foreach ($arr as $index => $item) {
         $maps[$item['id']] = &$arr[$index];
     }
     $returnList = array();
     foreach ($arr as $index => $item) {
         if ($item['pid'] !== -1) {
             if (!isset($maps[$item['pid']]['child'])) {
                 $maps[$item['pid']]['child'] = array();
             }       
             $maps[$item['pid']]['child'][] = &$maps[$item['id']];
         } else {
             $returnList[] = &$maps[$item['id']];
         }
     }
     var_dump($returnList);exit;
     echo json_encode($returnList);
    

    二叉树

    https://segmentfault.com/a/1190000009370316
    https://blog.csdn.net/baidu_30000217/article/details/52953127

    class TreeNode {
        public $val = null;
        public $left = null;
        public $right = null;
    
        function __construct($value) {
            $this->val = $value;
        }
    }
    

    先序遍历

    //二叉树先序遍历  递归版
        public List<Integer> preorderTraversal(TreeNode root) {
            List<Integer> res = new ArrayList<Integer>();
            preorderHelper(root, res);
            return res;
        }
    
        public void preorderHelper(TreeNode root, List<Integer> res) {
            if (root == null) {
                return;
            }
    
            res.add(root.val);
            if (root.left != null) {
                preorderHelper(root.left, res);
            }
    
            if (root.right != null) {
                preorderHelper(root.right, res);
            }
        }
    
        //二叉树先序遍历  非递归版
        public List<Integer> preorderTraversal2(TreeNode root) {
            LinkedList<TreeNode> stack = new LinkedList<TreeNode>();
            List<Integer> res = new ArrayList<Integer>();
            if (root == null) {
                return res;
            }
            stack.push(root);
            while (!stack.isEmpty()) {
                TreeNode tmp = stack.poll();
                res.add(tmp.val);
                if (tmp.right != null) {
                    stack.push(tmp.right);
                }
    
                if (tmp.left != null) {
                    stack.push(tmp.left);
                }
            }
            return res;
        }
    

    后序遍历

    //二叉树后序遍历 递归版
        public List<Integer> postorderTraversal(TreeNode root) {
            List<Integer> res = new ArrayList<Integer>();
            postOrderHelper(root, res);
            return res;
        }
    
        public void postOrderHelper(TreeNode root, List<Integer> res) {
            if (root == null) {
                return;
            }
            if (root.left != null) {
                postOrderHelper(root.left, res);
            }
    
            if (root.right != null) {
                postOrderHelper(root.right, res);
            }
            res.add(root.val);
        }
    
        //二叉树后序遍历 非递归版
        public List<Integer> postorderTraversal2(TreeNode root) {
            List<Integer> res = new ArrayList<Integer>();
            if (root == null) {
                return res;
            }
            TreeNode head = root;
            LinkedList<TreeNode> stack = new LinkedList<TreeNode>();
            stack.push(root);
            while (!stack.isEmpty()) {
                TreeNode tmp = stack.peek();
                if ((tmp.left == null && tmp.right == null)
                        || tmp.left == head
                        || tmp.right == head
                ) {
                    res.add(tmp.val);
                    stack.poll();
                    head = tmp;
                } else {
                    if (tmp.right != null) {
                        stack.push(tmp.right);
                    }
                    if (tmp.left != null) {
                        stack.push(tmp.left);
                    }
                }
            }
            return res;
        }
    

    中序遍历

    左根右

    /**
         * @param TreeNode $root
         * @return Integer[]
         * @brief 二叉树中序遍历(递归) 左->根->右
         */
        function inorderTraversal($root) {
            if (!is_null($root)) {
                $func = __FUNCTION__;
                $this->$func($root->left);
                echo $root->val . ",";
                $this->$func($root->right);
            }
        }
    
        /**
         * inorder
         * @param TreeNode $root
         * @return void
         * @brief 中序遍历非递归版本
         * 1.循环将左子树插入栈
         * 2.pop栈,打印当前节点val
         * 3.将pop栈出来的节点循环第1个步骤
         */
        function inorder($root) {
            if (!$root) {
                return;
            }
            $stack = new splstack;
            while ($root || !$stack->isEmpty()) {
    
                //循环将左子树push入stack
                while ($root) {
                    $stack->push($root);
                    $root = $root->left;
                }
                //pop stack,打印当前val
                $root = $stack->pop();
                echo $root->val . ",";
                //继续针对右子数循环上述
                $root = $root->right;
            }
        }
    

    广度优先遍历

        /**
         * leverOrder
         * @param TreeNode $root
         * @return void
         * @brief 广度优先遍历
         */
        function leverOrder($root) {
            $queue = new splqueue();
            $queue->enqueue($root);
            while (!$queue->isEmpty()) {
                $root = $queue->dequeue();
                echo $root->val . ",";
    
                if ($root->left) {
                    $queue->enqueue($root->left);
                }
    
                if ($queue->right) {
                    $queue->enqueue($root->right);
                }
            }
        }
    

    树的深度

    /**
         * getDepth
         * @param TreeNode $root
         * @return int
         * @brief 获取树的深度
         */
        function getDepth($root) {
            if (!$root) {
                return 0;
            }
            //叶子节点
            if (!$root->left && !$root->right) {
                return 1;
            }
            $leftDepth  = $this->getDepth($root->left);
            $rightDepth = $this->getDepth($root->right);
            $maxDepth   = $rightDepth >= $leftDepth ? $rightDepth : $leftDepth;
            $depth      = $maxDepth + 1;
            return $depth;
        }
    

    判断一个树是不是BST,二叉搜索树

    方法一:中规中矩,没毛病,中序遍历,然后判断结论是否递增

        /**
         * @param TreeNode $root
         * @return Boolean
         * @bierf 判断一个树是不是二叉搜索树 BST
         * 方法1:中序遍历二叉树,判断结果是不是递增
         */
        function isValidBST1($root) {
            $outArr = $this->inorderTraversal($root);
            $tmp    = 0;
            foreach ($outArr as $item) {
                if ($tmp <= $item) {
                    $tmp = $item;
                } else {
                    return false;
                }
            }
            return true;
        }
    

    方法二:
    利用搜索二叉树的特性,左<中<右
    有一个很有意思的例子,请拿这个例子来看看下面的算法对不对


    image.png
      /**
         * @param TreeNode $root
         * @return Boolean
         * @bierf 判断一个树是不是二叉搜索树 BST
         * 方法2:判断左子树和右子树与根节点的大小关系
         */
        function isValidBST2($root) {
            return $this->valiadBST($root, PHP_INT_MIN, PHP_INT_MAX);
        }
    
        /**
         * valiadBST
         * @param TreeNode $root
         * @param $min
         * @param $max
         * @return bool
         */
        function valiadBST($root, $min, $max) {
            if (!$root) {
                return true;
            }
    
            if (($root->val <= $min) || ($root->val >= $max)) {
                return false;
            }
    
            $flag1 = $this->valiadBST($root->left, $min, $root->val);
            $flag2 = $this->valiadBST($root->right, $root->val, $max);
            return $flag1 && $flag2;
        }
    

    二叉排序数的生成

    利用二叉搜索数的特性,左子树的所有值小于根节点,右子树的所有值大于根节点,所以以i为根节点,左子树为(1,i-1),右子树为(i+1,n),
    参考链接
    参考链接2

        /**
         * generateBST
         * @param $n
         * @return void
         */
        function generateBST($n) {
            $r = $this->genHelper(1, $n);
            return $r;
        }
    
    /**
         * genHelper
         * @param $left
         * @param $right
         * @return $res
         */
        function genHelper($left, $right) {
            $res = array();
            if ($left > $right) {
                $res[] = null;
                return $res;
            }
    
            for ($i = $left; $i <= $right; $i++) {
                $leftList  = $this->genHelper($left, $i - 1);
                $rightList = $this->genHelper($i + 1, $right);
                for ($j = 0; $j < count($leftList); $j++) {
                    for ($k = 0; $k < count($rightList); $k++) {
                        $root        = new TreeNode($i);
                        $root->left  = $leftList[$j];
                        $root->right = $rightList[$k];
                        $res[]       = $root;
                    }
                }
            }
    
            return $res;
        }
    

    中序遍历和先序遍历生成搜索二叉树

    https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/submissions/
    解析:先序遍历 preorder 根左右,中序遍历inorder左根右,通过先序遍历找到根节点的值,通过这个值在中序遍历中分别找到左子树和右子树的order,然后继续基于左子树和右子树的preorder 和inorder迭代
    划重点:这个二叉树中没有重复的值,这是这个题目的先决条件,否则在中序遍历的array中查找根节点时,会出问题

     /**
         * @param Integer[] $preorder
         * @param Integer[] $inorder
         * @return TreeNode
         * @brief 通过先序遍历和中序遍历还原一个BST
         */
        function buildTree($preorder, $inorder) {
            if (!$preorder || !$inorder) {
                return null;
            }
    
            return $this->buildHelper($preorder, 0, count($preorder) - 1, $inorder, 0, count($inorder) - 1);
        }
    
    
        /**
         * buildHelper
         * @param TreeNode $preorder
         * @param TreeNode $preL
         * @param $preR
         * @param $inorder
         * @param $inL
         * @param $inR
         * @return TreeNode
         */
        function buildHelper($preorder, $preL, $preR, $inorder, $inL, $inR) {
    
            if ($preL > $preR || $inL > $inR) {
                return null;
            }
            $root        = new TreeNode($preorder[$preL]);//先序遍历的第一个为root
            $index       = array_search($root->val, $inorder);//中序遍历的index
    
            //对于中序遍历 $index-$inL 就是左子树的长度,所以此时的$preR = $preL + $index - $inL
            $root->left  = $this->buildHelper($preorder, $preL + 1, $index - $inL + $preL, $inorder, $inL, $index - 1);
    
            //同理,$index-$inL为左子树的长度 所以右子树的起始位置是$preL = $preL + $index-$inL + 1
            $root->right = $this->buildHelper($preorder, $preL + $index - $inL + 1, $preR, $inorder, $index + 1, $inR);
            return $root;
        }
    

    中序遍历和后序遍历还原BST

    https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/submissions/
    类似先序遍历和中序遍历还原BST

     /**
         * buildTreeS
         * @param $inorder
         * @param $postorder
         * @return null|TreeNode
         * @brief 通过后序遍历和中序遍历还原一个BST
         */
        function buildTreeS($inorder, $postorder) {
            if (!$inorder || !$postorder) {
                return null;
            }
    
            return $this->buildSHelper($postorder, 0, count($postorder) - 1, $inorder, 0, count($inorder) - 1);
    
        }
    
        /**
         * buildSHelper
         * @param $postorder
         * @param $pL
         * @param $pR
         * @param $inorder
         * @param $inL
         * @param $inR
         * @return null|TreeNode
         */
        function buildSHelper($postorder, $pL, $pR, $inorder, $inL, $inR) {
            if ($pL > $pR || $inL > $inR) {
                return null;
            }
            $root  = new TreeNode($postorder[$pR]);//后续遍历的最后一个一定是根节点
            $index = array_search($postorder[$pR], $inorder);//找到根节点在中序遍历的位置
    
            $root->left  = $this->buildSHelper($postorder, $pL, $pL + $index - $inL - 1, $inorder, $inL, $index - 1);
            $root->right = $this->buildSHelper($postorder, $pL + $index - $inL, $pR-1, $inorder, $index + 1, $inR);
            return $root;
        }
    

    数组生成BST

    已排好序的数组,生成BST:https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/

      /**
         * @param Integer[] $nums
         * @return TreeNode
         * @brief 已排好序的array,生成BST,
         */
        function sortedArrayToBST($nums) {
            return $this->sortArrHelper($nums, 0, count($nums) - 1);
        }
    
        /**
         * sortArrHelper
         * @param $arr
         * @param $left
         * @param $right
         * @return null|TreeNode
         */
        function sortArrHelper($arr, $left, $right) {
            if ($left > $right) {
                return null;
            }
            $mid         = intval(($left + $right) / 2);
            $midVal      = $arr[$mid];
            $root        = new TreeNode($midVal);
            $root->left  = $this->sortArrHelper($arr, $left, $mid - 1);
            $root->right = $this->sortArrHelper($arr, $mid + 1, $right);
            return $root;
        }
    

    基于深度优先遍历从下到上输出BST

    https://leetcode.com/problems/binary-tree-level-order-traversal-ii/submissions/

    image.png
    • splqueue 的dequeue是从队尾弹出,pop是从队头弹出(pop是保证先进先出)
    /**
         * levelOrderBottom
         * @param TreeNode $root
         * @return void
         *
         */
        function levelOrderBottom($root) {
            if (!$root) {
                return [];
            }
            $queue = new splqueue();
            $queue->push($root);
            $res = array();
            while (!$queue->isEmpty()) {
                $count  = $queue->count();
                $tmpArr = [];
                for ($i = 0; $i < $count; $i++) {
                    $root = $queue->dequeue();
    
                    $tmpArr[] = $root->val;
    
                    if ($root->left) {
                        $queue->push($root->left);
                    }
    
                    if ($root->right) {
                        $queue->push($root->right);
                    }
                }
                array_unshift($res, $tmpArr);
            }
            return $res;
        }
    

    判断一个二叉树是不是平衡二叉树

        /**
         * @param TreeNode $root
         * @return Boolean
         */
        function isBalanced($root) {
            if (!$root) {
                return true;
            }
            $leftDepth  = $this->getDepth($root->left);
            $rightDepth = $this->getDepth($root->right);
            if (abs($leftDepth - $rightDepth) > 1) {
                return false;
            }
    
            return $this->isBalanced($root->left) && $this->isBalanced($root->right);
    
        }
    

    Path Sum

    题目连接:https://leetcode.com/problems/path-sum-ii/
    给定一个二叉树和一个int数值,找出所有的根节点到叶子节点的组合,指的根节点到叶子节点的路径上的和等于该int值


    深度优先遍历树,将每次遍历的val存入一个一维数组res,当发现遍历到某个叶子节点并且刚好节点值的和为sum,则此res就是一个解集,存入最终结果集arr二维数组。
    如果发现该节点对应子树没有能找到结果集,则要将节点pop出res集合

        /**
         * @param TreeNode $root
         * @param Integer $sum
         * @return Integer[][]
         */
        function pathSum($root, $sum) {
            $res = [];
            $arr = [];
            $this->pathSumHelper($root,$sum,$res,$arr);
            return $arr;
        }
    
        /**
         * pathSumHelper
         * @param TreeNode $root
         * @param $sum
         * @param $res
         * @param $arr
         * @return void
         */
        function pathSumHelper($root, $sum, &$res, &$arr){
            if (!$root) {
                return;
            }
            $res[] = $root->val;
            $sum   = $sum - $root->val;
    
            if (!$sum && !$root->right && !$root->left) {
                $arr[] = $res;
            }
    
            $this->pathSumHelper($root->left, $sum, $res, $arr);
            $this->pathSumHelper($root->right, $sum, $res, $arr);
            array_pop($res);//精髓pop,
        }
    

    测试case:

    $tree1        = new TreeNode(5);
    $tree2       = new TreeNode(4);
    $tree3       = new TreeNode(8);
    $tree4       = new TreeNode(11);
    $tree5       = new TreeNode(13);
    $tree6       = new TreeNode(4);
    $tree7       = new TreeNode(7);
    $tree8       = new TreeNode(2);
    $tree9       = new TreeNode(5);
    $tree10       = new TreeNode(1);
    $tree1->left = $tree2;
    $tree1->right = $tree3;
    $tree2->left = $tree4;
    $tree4->left = $tree7;
    $tree4->right = $tree8;
    $tree3->left = $tree5;
    $tree3->right = $tree6;
    $tree6->left = $tree9;
    $tree6->right = $tree10;
    $so          = new Solution();
    $r           = $so->pathSum($tree1,22);
    var_dump($r);
    exit;
    

    Has Path Sum

    path sum的简化版,只需要找出是否存在路径和等于sum,不用列举具体路径

    /**
         * hasPathSum
         * @param $root
         * @param $sum
         * @return bool
         */
        function hasPathSum($root, $sum) {
    
            if(!$root){
                return false;
            }
            if ($sum == $root->val && !$root->left && !$root->right) {
                return true;
            }
            $flagL = $this->hasPathSum($root->left, $sum - $root->val);
            $flagR = $this->hasPathSum($root->right, $sum - $root->val);
            return $flagL || $flagR;
        }
    

    Flatten Binary Tree to Linked List

    https://leetcode.com/problems/flatten-binary-tree-to-linked-list/
    将一个二叉树转化为链表形式

     /**
         * @param TreeNode $root
         * @return NULL
         * @brief https://leetcode.com/problems/flatten-binary-tree-to-linked-list/
         */
        function flatten($root) {
            $res = new TreeNode(PHP_INT_MAX);
            $this->flattenHelper($root, $res, $out);
            $root = $out;
            return $out;
        }
    
        /**
         * flattenHelper
         * @param TreeNode $root
         * @param TreeNode $res
         * @return void
         */
        function flattenHelper($root, &$res, &$out) {
    
            if (!$root) {
                return;
            }
            $newRoot = new TreeNode($root->val);
            if ($res->val == PHP_INT_MAX) {
                $res = $newRoot;
                $out = $res;
            } else {
                $res->right = $newRoot;
                $res        = $res->right;
            }
    
            $this->flattenHelper($root->left, $res, $out);
            $this->flattenHelper($root->right, $res, $out);
            return;
        }
    

    数组生成二叉树

    根据数组,生成二叉树
    例如:[7, -10, 2, -4, 3, -8, null, null, null, null, -1, 11]生成


    image.png
        /**
         * createTree2
         * @param TreeNode $root
         * @param $arr
         * @param $len
         * @param $index
         * @return void
         */
        function createTree2(&$root, $arr, $len, $index) {
            if ($index >= $len) {
                return;
            }
            $val  = $arr[$index];
            $root = new TreeNode($val);
            $this->createTree2($root->left,$arr,$len,2 * $index + 1);
            $this->createTree2($root->right,$arr,$len,2 * $index + 2);
        }
    

    最小公共父节点

    https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/
    给定一个二叉树root,同时给定root的两个子树p和q,求p和q的最小公共父节点

    递归大法,如果当前节点不等于p或者q,那么p或者q一定在当前节点的子节点中,有三种情况
    1.p,q都位于左子树,这里有两种情况,一种情况是left会返回p和q中较高的那个位置,而right会返回空,所以我们最终返回非空的left即可,这就是题目中的例子2的情况。还有一种情况是会返回p和q的最小父结点,就是说当前结点的左子树中的某个结点才是p和q的最小父结点,会被返回。
    2.p,q都位于右子树,同样这里有两种情况,一种情况是right会返回p和q中较高的那个位置,而left会返回空,所以我们最终返回非空的right即可,还有一种情况是会返回p和q的最小父结点,就是说当前结点的右子树中的某个结点才是p和q的最小父结点,会被返回
    3.p,q分别位于左子树和右子树,这种情况,分别对左子树和右子树调用递归,一定会返回p或q的公共节点

     /**
         * lowestCommonAncestor
         * @param TreeNode $root
         * @param TreeNode $p
         * @param TreeNode $q
         * @return void
         */
        function lowestCommonAncestor($root, $p, $q) {
            if (!$root || $p == $root || $q == $root) {
                return $root;
            }
            $left  = $this->lowestCommonAncestor($root->left, $p, $q);
            $right = $this->lowestCommonAncestor($root->right, $p, $q);
            if ($left && $right) {
                return $root;
            }
            return $left ? $left : $right;
        }
    

    相关文章

      网友评论

          本文标题:Tree

          本文链接:https://www.haomeiwen.com/subject/fndjuxtx.html