首页 > 其他分享 >平衡二叉树AVL

平衡二叉树AVL

时间:2023-10-30 15:11:21浏览次数:33  
标签:node 左子 结点 右子 AVL 二叉树 平衡 节点

在计算机科学中,AVL树是最早被发明的自平衡二叉查找树。在AVL树中,任一节点对应的两棵子树的最大高度差为1,因此它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下的时间复杂度都是 $O(logn)$。所以我们可知,AVL树首先是二叉查找树(BST),不了解BST的同学可以了解一下,因为AVL树在添加节点和删除节点时,要保持平衡性质,就需要根据BST的性质来调整。节点的平衡因子是它的左子树的高度减去它的右子树的高度(有时相反),带有平衡因子1、0或-1的节点被认为是平衡的。下面是一个AVL树的例子:

image

所以根据以上描述,AVL树有以下性质:

  1. 若任一节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  2. 若任一节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  3. 任意节点的左、右子树也分别为二叉查找树;
  4. 没有键值相等的节点;
  5. 任一节点对应的两棵子树的最大高度差为1。

AVL树旋转

如果一棵树不符合AVL的性质,我们该怎么办呢?这就需要动态地调整二叉树,称之为旋转,通过旋转最小失衡树来调整。在新插入的结点向上查找,以第一个平衡因子的绝对值超过1的结点为根的子树称为最小不平衡子树。对于AVL树来说,失衡的情况可以分如下几种:LL,RR,LR,RL。

LL

对于任意节点,如果左子树的高度与右子树的高度差大于1,并且子树没有失衡的情况,这种被称为LL型,如下图所示:

image

此时需要进行一次右旋操作:

  1. 以当前根结点(3)的左子树根结点(2)作为根结点;
  2. 将原来的根结点(3)作为现在根结点(2)的右子树根结点;
  3. 将原来左子树根结点(2)的右子树作为原来根结点的左子树

上面转移的规则其实很好理解,由于左子树较高,所以需要向右侧转移,达到平衡效果,由于AVL树拥有二叉搜索树的特性,左子树的值比右子树的值小,所以当前根结点(3)必大于2的右子树根结点(这里为NIL),所以3作为2的左子树根结点,那么2的右子树根结点就只能作为3的左子结点了。下面的都是这种规则,不再进行分析了。旋转代码如下:

/**
 * 右旋,失衡情况对应LL
 *
 * @param node 当前子树根结点
 * @return 旋转后的根结点
 */
public AVLNode<E> rotateRight(AVLNode<E> node) {
    Objects.requireNonNull(node, "node must be not null");

    // 暂存当前节点
    AVLNode<E> originNode = node;
    // 当前节点的左子节点
    AVLNode<E> leftNode = node.left;
    if (leftNode == null)
        return node;
    originNode.left = leftNode.right;
    // 替换根结点
    node = leftNode;
    node.right = originNode;

    return node;
}

RR

image

此时需要进行一次左旋操作:

  1. 以当前根节点(1)的右子树根结点(2)作为根结点;
  2. 将原来的根结点(1)作为现在根结点(2)的左子树根结点;
  3. 将原来右子树根结点(2)的左子树作为原来根结点的右子树
/**
 * 左旋,失衡情况对应RR
 *
 * @param node 当前子树根结点
 * @return 旋转后的根结点
 */
public AVLNode<E> rotateLeft(@NotNull AVLNode<E> node) {
    Objects.requireNonNull(node, "node must be not null");

    // 暂存当前节点
    AVLNode<E> originNode = node;
    // 当前节点的右子结点
    AVLNode<E> rightNode = node.right;
    if (rightNode == null)
        return node;
    // 以当前根节点的右子树根结点作为根结点
    originNode.right = rightNode.left;
    // 替换根结点
    node = rightNode;
    node.left = originNode;

    return node;
}

LR

image

image

LL 和 RR在进行一次旋转操作之后,就达到了平衡,

RL

image

image

参考:


title: 平衡二叉树AVL
tags: [数据结构, 二叉树]
author: Mingshan
categories: [数据结构, 二叉树]
date: 2019-08-20

标签:node,左子,结点,右子,AVL,二叉树,平衡,节点
From: https://www.cnblogs.com/mingshan/p/17793501.html

相关文章

  • 数据结构之树(二叉树)
    什么是二叉树(binarytree)?在树结构的基础上,要求其中每个节点最多有两个子节点(一个节点最多有2个边)。二叉树由根节点和若干个左子树和右子树构成,这些子树也都是二叉树。二叉树可以为空树,也可以只包含一个根节点。为什么树形结构常用二叉树呢?就是为了省空间。n叉树,n越大就需要更......
  • 系统集成易混淆知识点汇总-资源平衡、资源平滑
    概念:(1)资源平衡:为了在资源需求与资源供给之间取得平衡,根据资源制约对开始日期和结束日期进行调整的一种技术。(2)资源平滑:对进度模型中的活动进行调整,从而使项目资源需求不超过预定资源限制的一种技术。区别:(1)资源平衡不受浮动时间的约束,资源平滑只能在浮动时间允许的范围内进行。......
  • PMP资源优化技术:资源平衡、资源平滑
    资源优化的定义:资源优化用于调整活动的开始和完成日期,以调整计划使用的资源,使其等于或少于可用的资源。资源优化技术是根据资源供给需求的情况,来调整进度模型的技术。(一)、资源平衡为了在资源需求与资源供给之间取得平衡,根据资源制约对开始日期和结束日期进行调整的一种技术。如......
  • 代码随想训练营第十六天(Pyhton)| 104.二叉树的最大深度、 111.二叉树的最小深度、222.完
    104.二叉树的最大深度1、后续遍历递归法classSolution:defmaxDepth(self,root:Optional[TreeNode])->int:ifrootisNone:return0left_depth=self.maxDepth(root.left)#左right_depth=self.maxDepth(root.right)#......
  • C++从std::vector<int>类型数据创建二叉树
    背景在和chatGPT的日常代码交流中,这位“老师”总能给出不不少好代码,以下就是C++从std::vector类型数据创建二叉树的完整代码段:TreeNode*createBinaryTree(conststd::vector<int>&nodes,intindex){if(index>=nodes.size()||nodes[index]==-1){retu......
  • [Leetcode] 0104. 二叉树的最大深度
    104.二叉树的最大深度题目描述给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明: 叶子节点是指没有子节点的节点。示例:给定二叉树[3,9,20,null,null,15,7],3/\920/\157返回它的最大深度 3。......
  • 如何平衡表单设计过程中用户体验与企业管控需求(上)
    作者:胡庆星大家都听说过这句话,叫做“制度流程化、流程表单化、表单信息化、信息标准化”,这句话简要的概括了系统落地的路径,核心体现了两个方面的内容,表单即管理,它对上承接管理制度与流程的落地,体现管理思路和意志,另外表单是指导数据标准化落地的工具,是设计业务对象、逻辑模型、物理......
  • 【数据结构】- 平衡树
    平衡树简介平衡树是可以维护权值信息的数据结构。平衡树通过对二叉搜索树树高的平衡调整优化插入、删除、修改和查找的复杂度。故而节点其实形成了一个二叉树的形态,通过特定函数支持了查询序列中元素的前驱/后继,排名和特定排名的元素等有关权值的信息。根据平衡树结构特性,也......
  • 94.二叉树的中序遍历
    1.题目介绍给定一个二叉树的根节点root,返回它的中序遍历。示例1:输入:root=[1,null,2,3]输出:[1,3,2]示例2:输入:root=[]输出:[]示例3:输入:root=[1]输出:[1]提示:树中节点数目在范围[0,100]内-100<=Node.val<=1002.题解2.1递归首先我们需......
  • STL之AVL模拟的实现(万字长文详解)
    STL之AVL模拟的实现AVL树的概念为什么会有AVL树?在STL中对map/multimap/set/multiset其底层都是按照二叉搜索树来实现的,但是二叉搜索树有其自身的缺陷,假如往树中插入的元素有序或者接近有序,二叉搜索树就会退化成单支树,时间复杂度会退化成O(N),因此map、set等关联式容器的底层结......