zoukankan      html  css  js  c++  java
  • 数据结构-树

    树结构是天然的组织结构,如计算机中的文件夹,mysql的存贮结构。

    使用树结构存储后,出奇高效

    分布:

    • 二分搜索树
    • 平衡二叉树:AVL;红黑树
    • 堆;并查集
    • 线段树;Tire(字典树,前缀树)

    二叉树

    image

    • 和链表一样,动态的数据结构
    • 二叉树具有唯一根节点
    • 二叉树每个节点最多两个孩子
    • 每个节点最多一个父亲
    • 二叉树具有天然递归结构
    • 每个节点的左子树也是二叉树
    • 每个节点的右子树也是二叉树
    • 二叉树不一定是'满'的(一个节点也是二叉树,空也是)
    Class Node{
        E e;
        Node left;
        Node right;
    }
    
    • 二叉树(多叉树)

    二分搜索树

    • 二分搜索树也是二叉树
    • 二分搜索树的每个节点的值:
      • 大于其左子树的所有节点的值
      • 小于其右子树的所有节点的值
    • 每个子树也是二分搜索树

    添加新元素

    二分搜索树不包含重复元素,如果想包含重复元素的话,只需定义:左子树小于等于节点;或者右子树大于等于节点。(注意数组链表支持重复元素)

    二分搜索树添加元素的非递归写法和链表很像。

    遍历

    遍历类型:前序遍历、中序遍历、后序遍历(递归、队列、栈)、层序遍历

    层序遍历:

    image

    栈实现示意图:
    image

    二分搜索树的非递归实现比递归实现复杂很多;

    中序遍历和后序遍历的非递归实现更复杂;

    中序遍历和后序遍历的非递归实现,实际运用不广;

    删除操作

    删除最小节点和最大节点相对来说是容易的

    image

    删除任意元素,需要考虑多种情况。

    删除节点右边有孩子:
    image

    删除节点左边有孩子,右边无孩子:
    image

    二分搜索树操作代码

    <?php
    
    /**二分搜索树操作
     * Class TreeBinarySearch
     * @package appmodels
     */
    class TreeBinarySearch
    {
        public $val = null;
        public $left = null;
        public $right = null;
        public $size=0;
    
        public function __construct($value=null){
            $this->val = $value;
        }
    
    
        /**添加元素
         * @param $value
         * @return TreeBinarySearch
         */
        public function add( $value ){
            $node = $this;
            return $this->add2($node,$value);
        }
    
        public function selectBinary( $node, $value  ){
    
            if($node==null)
                return false;
    
            if( $node->val == $value ){
                return $node;
            }
    
            if( $node->val > $value ){
                return  $this->selectBinary($node->left,$value);
            }else{
                return  $this->selectBinary($node->right,$value);
            }
    
        }
    
        /**查询
         * @param string $type 'pre'前序遍历,'in'中序遍历,'last'后序遍历
         */
        public function select( $value=null,$type='pre' ){
            if($value)
                return $this->selectBinary($this,$value);
    
            switch ( $type ){
                case 'pre':
                    return $this->selectPreorderByStack($this);
                    break;
                case 'in':
                    return $this->selectInorder($this);    //中序结果是顺序结构
                    break;
                case 'last':
                    return $this->selectLastorder($this);   //后序遍历 应用:未二分搜索树释放内存
                    break;
            }
        }
    
        /**
         * 查询最小值
         */
        public function selectMin( $node ){
            if( $node->left != null ){
                $this->selectMin($node->left);
            }
    
            return $node;
    
        }
    
        /**
         * 查询最大值
         */
        public function selectMax( $node ){
            if( $node->right != null ){
                $this->selectMax($node->right);
            }
    
            return $node;
        }
    
        public function add2( $node,$value ){
            if(!is_object($node)){
                $node = new TreeBinarySearch(null);
            }
    
            if( $node->val == $value ){
                return $node;
            }
    
            if( $node->val == null ){
                $node->val = $value;
                $this->size++;
                return $node;
            }
    
            if( $node->val > $value){
                 $node->left = $this->add2($node->left,$value);
            }
    
            if( $node->val < $value ){
                 $node->right = $this->add2($node->right,$value);
            }
    
            return $node;
        }
    
    
        /**
         * 前序遍历
         */
        public function selectPreorder($node,$level=1){
            if( $node == null ){
                return;
            }
    
            echo $this->deepShow($level);
            echo $node->val . "
    ";
    
            $this->selectPreorder($node->left,$level+1);
    
            $this->selectPreorder($node->right,$level+1);
        }
    
    
        /**
         *  前序遍历(栈)
         */
        public function selectPreorderByStack($node){
            //栈
            $stack = [];
            array_push($stack,$node);
            while (!empty($stack)){
    
                $cur = array_pop($stack);
    
                echo $cur->val . "
    ";
    
    
                if( $cur->right ){
                    $stack[] = $cur->right;
                }
    
                if( $cur->left ){
                    $stack[] = $cur->left;
                }
            }
        }
    
        /**
         * 中序遍历
         */
        public function selectInorder($node,$level=1){
            if( $node == null ){
                return;
            }
    
            $this->selectInorder($node->left,$level+1);
    
            echo $this->deepShow($level);
            echo $node->val . "
    ";
    
            $this->selectInorder($node->right,$level+1);
        }
    
        /**
         * 中序遍历(栈)
         */
        public function selectInorderByStack($node){
    
            $stack = [$node];
            while( !empty($stack) ){
    
                $cur = array_pop($stack);
    
                if( $cur->left ){
                    $stack[] = $cur->left;
                }else{
                    echo $cur->val . "
    ";
                }
    
    
                if( $cur->right ){
                    $stack[] = $cur->right;
                }else{
                    echo $cur->val . "
    ";
                }
    
    
    
    
            }
    
    
    
        }
    
        /**
         * 后序遍历
         */
        public function selectLastorder($node,$level=1){
            if( $node == null ){
                return;
            }
    
            $this->selectLastorder($node->right,$level+1);
    
            echo $this->deepShow($level);
            echo $node->val . "
    ";
    
            $this->selectLastorder($node->left,$level+1);
    
        }
    
    
        /**
         * 树深度
         */
        protected function deepShow($deep){
            while($deep--){
                echo '--';
            }
        }
    
        /**
         * 删除最小节点
         * @param TreeBinarySearch $node
         */
        public function deleteMin( $node ){
            if( $node->left==null ){
                $rightNode = $node->right;
                $node->right = null;
                $this->size--;
                return $rightNode;
            }
    
            $node->left = $this->deleteMin($node->left);
            return $node;
        }
    
        /**
         * 删除最大节点
         * @param  TreeBinarySearch $node
         */
        public function deleteMax($node){
            if( $node->right == null ){
                $leftNode = $node->left;
                $node->left = null;
                $this->size--;
                return $leftNode;
            }
            $node->right = $this->deleteMax($node->right);
            return $node;
        }
    
        /**
         * 删除任意节点
         * @param $node
         * @param $value
         */
        public function delete($value){
            return $this->deleteByRecursion($this,$value);
        }
    
        public function deleteByRecursion($node,$value){
            if( $this->size==0 )
                throw new Exception('节点为空');
    
            //空返回错误
            if( $node==null )
                return false;
    
            //找到节点
            if(  $node->val != $value ){
                //先从左节点找 再又节点  性能较差
    //            return $this->deleteByRecursion($node->left,$value) or $this->deleteByRecursion($node->right,$value);
                //二分查找
                $node =  $this->select($value);
            }
    
            //目标节点左右节点为空 返回空
            if( $node->left==null && $node->right == null ){
                $node->val=null;
                $this->size--;
                return $node;
            }
    
            //右节点
            if( $node->right ){
                //获取右边最大值
                $nodeRightMin = $this->selectMin($node->right);
    
                //当前节点
                $node->val = $nodeRightMin->val;
                $node->right = $this->deleteMin($node->right);
            }else{
                //获取左节点最大值
                $nodeLeftMax = $this->selectMax($node->left);
                $node->val = $nodeLeftMax->val;
                $node->left = $this->deleteMax($node->left);
            }
    
            return $node;
        }
    
    
    }
    
  • 相关阅读:
    HDU 4315 Climbing the Hill [阶梯Nim]
    POJ 1704 Georgia and Bob [阶梯Nim]
    BZOJ 1874: [BeiJing2009 WinterCamp]取石子游戏 [Nim游戏 SG函数]
    BZOJ 1299: [LLH邀请赛]巧克力棒 [组合游戏]
    浏览器缓存知识点总结
    软件测试自动化的最新趋势
    性能测试面试题(附答案
    最流行的自动化测试工具,总有一款适合你
    49种软件测试方法
    linux执行jmeter脚本解决响应数据为空
  • 原文地址:https://www.cnblogs.com/followyou/p/11236323.html
Copyright © 2011-2022 走看看