PHP二叉树(二):平衡二叉树(AVL)

关于平衡二叉树的原理网上的资源就挺多的,而且情况有点小复杂,所以在这里我就不再陈述了,直接上代码吧:

<!--?php

/**

 * author:zhongjin

 * time:2016/10/20 11:53

 * description: 平衡二叉树

 */

//结点

class Node

{

    public $key;

    public $parent;

    public $left;

    public $right;

    public $bf; //平衡因子

  

    public function __construct($key)

    {

        $this--->key = $key;

        $this->parent = NULL;

        $this->left = NULL;

        $this->right = NULL;

        $this->bf = 0;

    }

}

  

//平衡二叉树

class Avl

{

    public $root;

    const LH = +1;  //左高

    const EH = 0;   //等高

    const RH = -1;  //右高

  

    /**

     * 初始化树结构

     * @param $arr 初始化树结构的数组

     * @return null

     */

    public function init($arr)

    {

        $this->root = new Node($arr[0]);

        for ($i = 1; $i < count($arr); $i++) {

            $this->Insert($arr[$i]);

        }

    }

  

    /**

     * (对内)中序遍历

     * @param $root (树或子树的)根节点

     * @return null

     */

    private function mid_order($root)

    {

        if ($root != NULL) {

            $this->mid_order($root->left);

            echo $root->key . "-" . $root->bf . "  ";

            $this->mid_order($root->right);

        }

    }

  

    /**

     * (对外)中序遍历

     * @param null

     * @return null

     */

    public function MidOrder()

    {

        $this->mid_order($this->root);

    }

  

    /**

     * 将以$root为根节点的最小不平衡二叉树做右旋处理

     * @param $root(树或子树)根节点

     * @return null

     */

    private function R_Rotate($root)

    {

        $L = $root->left;

        if (!is_NULL($root->parent)) {

            $P = $root->parent;

            if ($root == $P->left) {

                $P->left = $L;

            } else {

                $P->right = $L;

            }

            $L->parent = $P;

        } else {

            $L->parent = NULL;

        }

        $root->parent = $L;

        $root->left = $L->right;

        $L->right = $root;

        //这句必须啊!

        if ($L->parent == NULL) {

            $this->root = $L;

        }

    }

  

    /**

     * 将以$root为根节点的最小不平衡二叉树做左旋处理

     * @param $root(树或子树)根节点

     * @return null

     */

    private function L_Rotate($root)

    {

        $R = $root->right;

        if (!is_NULL($root->parent)) {

            $P = $root->parent;

            if ($root == $P->left) {

                $P->left = $R;

            } else {

                $P->right = $R;

            }

            $R->parent = $P;

        } else {

            $R->parent = NULL;

        }

        $root->parent = $R;

        $root->right = $R->left;

        $R->left = $root;

        //这句必须啊!

        if ($R->parent == NULL) {

            $this->root = $R;

        }

    }

  

    /**

     * 对以$root所指结点为根节点的二叉树作左平衡处理

     * @param $root(树或子树)根节点

     * @return null

     */

    public function LeftBalance($root)

    {

        $L = $root->left;

        $L_bf = $L->bf;

        switch ($L_bf) {

            //检查root的左子树的平衡度,并作相应的平衡处理

            case self::LH:    //新结点插入在root的左孩子的左子树上,要做单右旋处理

                $root->bf = $L->bf = self::EH;

                $this->R_Rotate($root);

                break;

            case self::RH:    //新节点插入在root的左孩子的右子树上,要做双旋处理

                $L_r = $L->right;   //root左孩子的右子树根

                $L_r_bf = $L_r->bf;

                //修改root及其左孩子的平衡因子

                switch ($L_r_bf) {

                    case self::LH:

                        $root->bf = self::RH;

                        $L->bf = self::EH;

                        break;

                    case self::EH:

                        $root->bf = $L->bf = self::EH;

                        break;

                    case self::RH:

                        $root->bf = self::EH;

                        $L->bf = self::LH;

                        break;

                }

                $L_r->bf = self::EH;

                //对root的左子树作左平衡处理

                $this->L_Rotate($L);

                //对root作右平衡处理

                $this->R_Rotate($root);

        }

    }

  

    /**

     * 对以$root所指结点为根节点的二叉树作右平衡处理

     * @param $root(树或子树)根节点

     * @return null

     */

    public function RightBalance($root)

    {

        $R = $root->right;

        $R_bf = $R->bf;

        switch ($R_bf) {

            //检查root的右子树的平衡度,并作相应的平衡处理

            case self::RH:    //新结点插入在root的右孩子的右子树上,要做单左旋处理

                $root->bf = $R->bf = self::EH;

                $this->L_Rotate($root);

                break;

            case self::LH:    //新节点插入在root的右孩子的左子树上,要做双旋处理

                $R_l = $R->left;   //root右孩子的左子树根

                $R_l_bf = $R_l->bf;

                //修改root及其右孩子的平衡因子

                switch ($R_l_bf) {

                    case self::RH:

                        $root->bf = self::LH;

                        $R->bf = self::EH;

                        break;

                    case self::EH:

                        $root->bf = $R->bf = self::EH;

                        break;

                    case self::LH:

                        $root->bf = self::EH;

                        $R->bf = self::RH;

                        break;

                }

                $R_l->bf = self::EH;

                //对root的右子树作右平衡处理

                $this->R_Rotate($R);

                //对root作左平衡处理

                $this->L_Rotate($root);

        }

    }

  

    /**

     * 查找树中是否存在$key对应的节点

     * @param $key 待搜索数字

     * @return $key对应的节点

     */

    public function search($key)

    {

        $current = $this->root;

        while ($current != NULL) {

            if ($current->key == $key) {

                return $current;

            } elseif ($current->key > $key) {

                $current = $current->left;

            } else {

                $current = $current->right;

            }

        }

        return $current;

    }

  

    /**

     * 查找树中的最小关键字

     * @param $root 根节点

     * @return 最小关键字对应的节点

     */

    function search_min($root)

    {

        $current = $root;

        while ($current->left != NULL) {

            $current = $current->left;

        }

        return $current;

    }

  

    /**

     * 查找树中的最大关键字

     * @param $root 根节点

     * @return 最大关键字对应的节点

     */

    function search_max($root)

    {

        $current = $root;

        while ($current->right != NULL) {

            $current = $current->right;

        }

        return $current;

    }

  

    /**

     * 查找某个$key在中序遍历时的直接前驱节点

     * @param $x 待查找前驱节点的节点引用

     * @return 前驱节点引用

     */

    private function predecessor($x)

    {

        //左子节点存在,直接返回左子节点的最右子节点

        if ($x->left != NULL) {

            return $this->search_max($x->left);

        }

        //否则查找其父节点,直到当前结点位于父节点的右边

        $p = $x->parent;

        //如果x是p的左孩子,说明p是x的后继,我们需要找的是p是x的前驱

        while ($p != NULL && $x == $p->left) {

            $x = $p;

            $p = $p->parent;

        }

        return $p;

    }

  

    /**

     * 查找某个$key在中序遍历时的直接后继节点

     * @param $x 待查找后继节点的节点引用

     * @return 后继节点引用

     */

    private function successor($x)

    {

        if ($x->left != NULL) {

            return $this->search_min($x->right);

        }

        $p = $x->parent;

        while ($p != NULL && $x == $p->right) {

            $x = $p;

            $p = $p->parent;

        }

        return $p;

    }

  

    /**

     * (对内)插入结点,如果结点不存在则插入,失去平衡要做平衡处理

     * @param $root 根节点 $key 待插入树的数字

     * @return null

     */

    private function insert_node(&$root, $key)

    {

        //找到了插入的位置,插入新节点

        if (is_null($root)) {

            $root = new Node($key);

            //插入结点成功

            return TRUE;

        } else {

            //在树中已经存在和$key相等的结点

            if ($key == $root->key) {

                //插入节点失败

                return FALSE;

            } //在root的左子树中继续搜索

            elseif ($key < $root->key) {

                //插入左子树失败

                if (!($this->insert_node($root->left, $key))) {

                    //树未长高

                    return FALSE;

                }

  

                //成功插入,修改平衡因子

                if (is_null($root->left->parent)) {

                    $root->left->parent = $root;

                }

  

                switch ($root->bf) {

                    //原来左右子树等高,现在左子树增高而树增高

                    case self::EH:

                        $root->bf = self::LH;

                        //树长高

                        return TRUE;

                        break;

                    //原来左子树比右子树高,需要做左平衡处理

                    case self::LH:

                        $this->LeftBalance($root);

                        //平衡后,树并未长高

                        return FALSE;

                        break;

                    //原来右子树比左子树高,现在左右子树等高

                    case self::RH:

                        $root->bf = self::EH;

                        //树并未长高

                        return FALSE;

                        break;

                }

            } //在root的右子树中继续搜索

            else {

                //插入右子树失败

                if (!$this->insert_node($root->right, $key)) {

                    //树未长高

                    return FALSE;

                }

                //成功插入,修改平衡因子

                if (is_null($root->right->parent)) {

                    $root->right->parent = $root;

                }

                switch ($root->bf) {

                    //原来左右子树等高,现在右子树增高而树增高

                    case self::EH:

                        $root->bf = self::RH;

                        //树长高

                        return TRUE;

                        break;

                    //原来左子树比右子树高,现在左右子树等高

                    case self::LH:

                        $root->bf = self::EH;

                        return FALSE;

                        break;

                    //原来右子树比左子树高,要做右平衡处理

                    case self::RH:

                        $this->RightBalance($root);

                        //树并未长高

                        return FALSE;

                        break;

                }

            }

        }

    }

  

    /**

     * (对外)将$key插入树中

     * @param $key 待插入树的数字

     * @return null

     */

    public function Insert($key)

    {

        $this->insert_node($this->root, $key);

    }

  

    /**

     * 获取待删除的节点(删除的最终节点)

     * @param $key 待删除的数字

     * @return 最终被删除的节点

     */

    private function get_del_node($key)

    {

        $dnode = $this->search($key);

        if ($dnode == NULL) {

            throw new Exception("结点不存在!");

            return;

        }

        if ($dnode->left == NULL || $dnode->right == NULL) { #如果待删除结点无子节点或只有一个子节点,则c = dnode

            $c = $dnode;

        } else { #如果待删除结点有两个子节点,c置为dnode的直接后继,以待最后将待删除结点的值换为其后继的值

            $c = $this->successor($dnode);

        }

  

        $dnode->key = $c->key;

        return $c;

    }

  

  

    /**

     * (对内)删除指定节点,处理该结点往上结点的平衡因子

     * @param $node 最终该被删除的节点

     * @return null

     */

    private function del_node($node)

    {

        if ($node == $this->root) {

            $this->root = NULL;

            return;

        }

  

        $current = $node;

        //现在的node只有两种情况,要么只有一个子节点,要么没有子节点

        $P = $current->parent;

        //删除一个结点,第一个父节点的平衡都肯定会发生变化

        $lower = TRUE;

        while ($lower == TRUE && !is_null($P)) {

            //待删除结点是左节点

            if ($current == $P->left) {

                if($current == $node){

                    if (!is_null($current->left)) {

                        $P->left = $current->left;

                    } else {

                        $P->left = $current->left;

                    }

                }

                $P_bf = $P->bf;

                switch ($P_bf) {

                    case self::LH:

                        $P->bf = self::EH;

                        $lower = TRUE;

                        $current = $P;

                        $P = $current->parent;

                        break;

                    case self::EH:

                        $P->bf = self::RH;

                        $lower = FALSE;

                        break;

                    case self::RH:

                        $this->RightBalance($P);

                        $lower = TRUE;

                        $current = $P->parent;

                        $P = $current->parent;

                        break;

                }

            } //右结点

            else {

                if($current == $node){

                    if (!is_null($current->left)) {

                        $P->right = $current->left;

                    } else {

                        $P->right = $current->left;

                    }

                }

                $P_bf = $P->bf;

                switch ($P_bf) {

                    case self::LH:

                        $this->LeftBalance($P);

                        $lower = TRUE;

                        $current = $P->parent;

                        $P = $current->parent;

                        break;

                    case self::EH:

                        $P->bf = self::LH;

                        $lower = FALSE;

                        break;

                    case self::RH:

                        $P->bf = self::LH;

                        $lower = TRUE;

                        $current = $P;

                        $P = $current->parent;

                        break;

                }

            }

        }

    }

  

    /**

     * (对外)删除指定节点

     * @param $key 删除节点的key值

     * @return null

     */

    public function Delete($key)

    {

        $del_node = $this->get_del_node($key);

        $this->del_node($del_node);

    }

  

    /**

     * (对内)获取树的深度

     * @param $root 根节点

     * @return 树的深度

     */

    private function getdepth($root)

    {

        if ($root == NULL) {

            return 0;

        }

        $dl = $this->getdepth($root->left);

  

        $dr = $this->getdepth($root->right);

  

        return ($dl > $dr ? $dl : $dr) + 1;

    }

  

    /**

     * (对外)获取树的深度

     * @param null

     * @return null

     */

    public function Depth()

    {

        return $this->getdepth($this->root);

    }

}

http://www.php.cn/php-weizijiaocheng-346804.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值