数据结构-PHP 平衡二叉树(AVL)

数据结构-PHP 平衡二叉树(AVL)

这篇文章主要介绍一下 平衡二叉树(AVL),对于 二分搜索树 来说,如果树上的 元素顺序 添加的,会导致数据退化成一个 链表,这样就会造成很严重的性能问题,此时就需要在 二分搜索树 的基础上,保证元素插入时平衡,在了解 AVL 之前,需要您对 二分搜索树 有一定的了解,可以参考之前的文章。

1.二分搜索树的问题

如下图所示,若向二分搜索树中添加的元素是按照 顺序 从小到大依次插入的,这样会导致最后节点退化成链表:
在这里插入图片描述

Tips:反过来依次从大到插入元素也会出现退化成 链表

2.二叉树节点高度标注示意图

在这里插入图片描述

Tips:平衡因子等于左儿子高度减去右儿子高度,如45 和这个节点平衡因子 -2

3.平衡二叉树特点

  • 对于任何一个节点,左儿子树右儿子树高度差(Δh)的绝对值不能超过 1高度差(Δh) 称为 平衡因子
  • 本质是带了平衡功能的二分搜索树
  • 平衡二叉树(AVL) 的高度(h)节点数之间的关系是 O(logn)级别的。

4.节点定义 PHP 代码

对于 二分搜索树 来说,AVL 需要在插入元素的时候保证 平衡,就需要引入节点高度(h),所以节点定义需要在 二分搜索树 节点定义的基础上增加一个 height 属性:

class AVLNode
{
    public $e;
    public $left = null;
    public $right = null;
    public $height = 1;

    /**
     * 构造函数 初始化节点数据
     * Node constructor.
     * @param $e
     */
    public function __construct($e)
    {
        $this->e = $e;
    }
}

5.计算平衡因子

平衡因子等于左儿子高度减去右儿子高度,代码如下:

    /**
     * 获取 AVL 节点的高度 h
     * @param AVLNode $node
     * @return int
     */
    private function getHeight(AVLNode $node)
    {
        if ($node == null) {
            return 0;
        }
        return $node->height;
    }
    /**
     * 获取节点平衡因子
     * @param AVLNode $node
     * @return int\
     */
    private function getBalanceFactor(AVLNode $node){
        if ($node == null){
            return 0;
        }
        return $this->getHeight($node->left) - $this->getHeight($node->right);
    }

6.更新节点高度

若递归插入元素时,需要更新节点高度,递归时当前节点高度 h = 1 + (左右儿子中最大h),代码如下:

 /**
     * 向 AVL 添加元素
     * @param $e
     */
    public function add($e)
    {
        $this->root = $this->recursionAdd($this->root, $e);
    }

    /**
     * 递归向 AVL 添加元素
     * @param Node $root
     * @param $e
     */
    private function recursionAdd($root, $e)
    {
        if ($root == null) { //若节点为空则添加元素 并且返回当前节点信息
            $root = new AVLNode($e);
            $this->size++;
        } elseif ($e < $root->e) { //若元素小于当前节点元素 则向左节点递归添加元素
            $root->left = $this->recursionAdd($root->left, $e);
        } elseif ($e > $root->e) { //若元素大于当前节点元素 则向右节点递归添加元素
            $root->right = $this->recursionAdd($root->right, $e);
        } //若元素等于当前节点元素 则什么都不做


		 //更新节点高度
        $root->height = 1 + ($this->getHeight($root->left) > $this->getHeight($root->right) ? $this->getHeight($root->left) : $this->getHeight($root->right));
        return $root;
    }

Tips:此处代码直接贴出之前 二分搜索树 代码添加元素方法。

7.判断二叉树是否为二分搜索树

若要判断二叉树是否为二分搜索树,则需要将二叉树中序遍历,若输出结果是按照顺序依次从小到大排列的,则表示该 二叉树 是一颗 二分搜索树,采用递归思想层序遍历然后将节点元素依次入队,代码如下,然后依次出队查看出队元素是否依次增大:

    /**
     * 判断二叉树是否为二分搜索树
     */
    public function isBST()
    {
        $queue = new QueueByLinkedList();
        $this->inOrder($this->root, $queue);
        do {
            $e = $queue->dequeue();
            if ($queue->getSize() > 0 && $e > $queue->getFront()) {
                return false;
            }
        } while ($queue->getSize() > 0);

        return true;
    }
	
	 /**
     * 中序遍历二分搜索树
     */
    private function inOrder($root, $queue)
    {
        if ($root != null) {
            $this->inOrder($root->left, $queue);
            $queue->enqueue($root->e);
            $this->inOrder($root->right, $queue);
        }
    }

8.判断二叉树是否为平衡二叉树(AVL)

若需要判断二叉树是否为平衡二叉树(AVL),则需要遍历二叉树,判断平衡因子 的绝对值是否大于 1,若大于 1 则不是 平衡二叉树(AVL),否则就是,代码如下,使用递归处理:

    /**
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值