AVL树概念

前面学习二叉查找树二叉树的各种遍历,但是其查找效率不稳定(斜树),而二叉平衡树的用途更多。查找相比稳定很多。(欢迎关注数据结构专栏)

  • AVL树是带有平衡条件的二叉查找树。这个平衡条件必须要容易保持。而且要保证它的深度是O(logN).
  • AVL的条件是左右树的高度差(平衡因子)不大于1;并且它的每个子树也都是平衡二叉树。
  • 对于平衡二叉树的最小个数,n0=0;n1=1;nk=n(k-1)+n(k-2)+1;(求法可以类比斐波那契!)

难点:AVL是一颗二叉排序树,用什么样的规则或者规律让它能够在复杂度不太高的情况下实现动态平衡呢?

不平衡概况



如果简单的以单节点看,大致有上面四种情形,并且他们的最后结果也是有的有所相近。只是:上下会变动。该在左面的还在左面,改在右面的还在右面



这只是针对在底部,对于可能出现的平衡要首先搞清楚:



所以针对四种不平衡,可能出现在底部,也可能出现在头,也可能出现在某个中间节点导致不平衡。 而我们只需要研究其首次不平衡点,解决之后整棵树即继续平衡。当然,在实际解决肯定会带上递归的思想解决问题。

四种平衡旋转方式


RR平衡旋转(左单旋转)



出现这种情况的原因是节点的右侧的右侧较深这时候不平衡节点需要左旋。再细看过程。

  • 再左旋的过程中,root(oldroot)节点下沉,中间节点(newroot)上浮.而其中中间节点(newroot)的右侧依然不变。
  • 它上浮左侧所以需要指向根节点(oldroot)(毕竟一棵树)。但是这样newroot原来左侧节点H空缺。而我们需要仍然让整个树完整并且满足二叉排序树的规则
  • 而刚好本来oldroot右侧指向newroot变成oldroot被newroot左侧指向。所以oldroot右侧空缺,刚好这个位置满足在oldroot的右侧。在newroot的左侧。.所以我们将H插入在这个位置。
  • 其中H可能为NULL。不过不影响操作!



    而左旋的代码可以表示为:
private node getRRbanlance(node oldroot) {//右右深,需要左旋
// TODO Auto-generated method stub
node newroot=oldroot.right;
oldroot.right=newroot.left;
newroot.left=oldroot;
oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1;
newroot.height=Math.max(getHeight(newroot.left),getHeight(newroot.right))+1;//原来的root的高度需要从新计算
return newroot;
}

LL平衡旋转(右单旋转)

而右旋和左旋相反,但是思路相同,根据上述进行替换即可!



代码:

private node getLLbanlance(node oldroot) {//LL小,需要右旋转
// TODO Auto-generated method stub
node newroot=oldroot.left;
oldroot.left=newroot.right;
newroot.right=oldroot;
oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1;
newroot.height=Math.max(getHeight(newroot.left),getHeight(newroot.right))+1;//原来的root的高度需要从新金酸
return newroot;
}

RL平衡旋转(先右后左双旋转)

产生不平衡的条件原因是:

  • root节点右侧左侧节点的深度高些,使得与左侧的差大于1.这个与我们前面看到的左旋右旋不同的是因为它的结构不能直接变一下就可以完成。
  • 因为对于右左结构,中间的最大,两侧的最小。但是下面的比上面大(下面在上面右侧)所以如果平衡的话,那么右左的R.L应该在中间,而R应该在右侧。原来的root在左侧。
  • 所以节点的变化浮动比较大,而且需要妥善处理各个子节点的移动使其满足二叉排序树的性质!
  • 期间考虑树高度变化即可!

这种双旋转其实也很简单。不要被外表唬住。基于前面的单旋转,双旋转有两种具体逻辑思路

思路1:两次旋转RR,LL



根据上图所圈的,先对底部使得底部的大小关系变化,使其在满足二叉平衡树的条件下还满足RR结构的二叉树。所以只需要对右节点R先进行右旋,再对ROOT进行左旋即可。

思路2:直接分析

根据初始和结果的状态,然后分析各个节点变化顺序。手动操作这些节点即可!

  • 首先根据ROOT,R,R.L三个节点变化。R.L肯定要在最顶层。左右分别指向ROOT和R。那么这其中R.left,ROOT.right发生变化(原来分别是R,L和R)暂时为空。而刚好根据左右大小关系可以补上R.L的左右节点
  • 这样思考整棵树也可以完成平衡,但是要考虑树的高度变化



    代码为:(注释部分为方案1)
private node getRLbanlance(node oldroot) {//右左深
// node newroot=oldroot.right.left;
// oldroot.right.left=newroot.right;
// newroot.right=oldroot.right;
// oldroot.right=newroot.left;
// newroot.left=oldroot;
// oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1;
// newroot.right.height=Math.max(getHeight(newroot.right.left),getHeight(newroot.right.right))+1;
// newroot.height=Math.max(getHeight(oldroot.left),getHeight(newroot.right))+1;//原来的root的高度需要从新金酸
oldroot.right =getLLbanlance(oldroot.right);
oldroot.height=Math.max(getHeight(oldroot.left), getHeight(oldroot.right))+1;
return getRRbanlance(oldroot); }

LR平衡旋转(先左后右单旋转)

根据上述RL修改即可

private node getLRbanlance(node oldroot) {
oldroot.left =getRRbanlance(oldroot.left);
oldroot.height=Math.max(getHeight(oldroot.left), getHeight(oldroot.right))+1;
return getLLbanlance(oldroot); }

java代码实现

  • 首先对于节点多个height属性。用于计算高度(平衡因子)
  • 插入是递归插入。递归一个来回的过程,去的过程进行插入。回的过程进行高度更新。和检查是否平衡。不要写全局递归计算高度,效率太低下。事实上高度变化只和插入和平衡有关,仔细考虑即不会有疏漏!





总结

测试情况:

  • AVL的理解需要时间,当然笔者的AVL自己写的可能有些疏漏,如果有问题还请各位一起探讨
  • 当然,除了插入,AVL还有删除等其他操作,(原理相似。删除后平衡)有兴趣可以一起研究。
  • 如果需要源码还请关注笔者公众号:公众号查看相关专题文章!
  • 如果对后端、爬虫、数据结构算法等感性趣欢迎关注我的个人公众号交流:bigsai(回复数据结构、爬虫、java等有精心准备资料一份!)

AVL树(二叉平衡树)详解与实现的更多相关文章

  1. 数据结构图文解析之:二叉堆详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  2. 二叉搜索树详解(Java实现)

    1.二叉搜索树定义 二叉搜索树,是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根 ...

  3. 树-二叉平衡树AVL

    基本概念 AVL树:树中任何节点的两个子树的高度最大差别为1. AVL树的查找.插入和删除在平均和最坏情况下都是O(logn). AVL实现 AVL树的节点包括的几个组成对象: (01) key -- ...

  4. 哈夫曼树(二)之 C++详解

    上一章介绍了哈夫曼树的基本概念,并通过C语言实现了哈夫曼树.本章是哈夫曼树的C++实现. 目录 1. 哈夫曼树的介绍 2. 哈夫曼树的图文解析 3. 哈夫曼树的基本操作 4. 哈夫曼树的完整源码 转载 ...

  5. AVL树的旋转操作详解

    [0]README 0.0) 本文部分idea 转自:http://blog.csdn.net/collonn/article/details/20128205 0.1) 本文仅针对性地分析AVL树的 ...

  6. java项目---用java实现二叉平衡树(AVL树)并打印结果(详)(3星)

    package Demo; public class AVLtree { private Node root; //首先定义根节点 private static class Node{ //定义Nod ...

  7. 从零开始学算法---二叉平衡树(AVL树)

    先来了解一些基本概念: 1)什么是二叉平衡树? 之前我们了解过二叉查找树,我们说通常来讲, 对于一棵有n个节点的二叉查找树,查询一个节点的时间复杂度为log以2为底的N的对数. 通常来讲是这样的, 但 ...

  8. 二叉搜索树、AVL平衡二叉搜索树、红黑树、多路查找树

    1.二叉搜索树 1.1定义 是一棵二叉树,每个节点一定大于等于其左子树中每一个节点,小于等于其右子树每一个节点 1.2插入节点 从根节点开始向下找到合适的位置插入成为叶子结点即可:在向下遍历时,如果要 ...

  9. Algorithms: 二叉平衡树(AVL)

    二叉平衡树(AVL):   这个数据结构我在三月份学数据结构结构的时候遇到过.但当时没调通.也就没写下来.前几天要用的时候给调好了!详细AVL是什么,我就不介绍了,维基百科都有.  后面两月又要忙了. ...

随机推荐

  1. C#后台HttpWebRequest模拟跨域Ajax请求,注册Windows服务到服务器上

    项目需求,暂且叫A.B公司吧.我们公司需要从A公司哪里读取机器上的数据,放到我们数据库中.然后再将数据库中存的数据,提供一个接口,B公司来调用,大概这个意思. 好了,言归正传.这个是之前做好的界面,用 ...

  2. Java学习笔记之---Servlet

    Java学习笔记之---Servlet (一)如何实现Servlet 1.实现javax.servlet.Servlet接口: 2.继承javax.servlet.GenericServlet类: 3 ...

  3. 基于Bitnami gitlab OVA包的gitlab 环境搭建

    前言 最近在折腾gitlab,本篇记录搭建的过程方便以后查找 环境 Windows server + VMware 安装 为方便本次我们直接采用Bitnami的VOA安装包(VOA格式可同时兼容Vir ...

  4. 转 python - Python在终端通过pip安装好包以后,在Pycharm中依然无法使用的解决办法

    转 https://blog.csdn.net/kouyi5627/article/details/80531442 在终端通过pip装好包以后,在pycharm中导入包时,依然会报错.新手不知道具体 ...

  5. 172. 阶乘后的零 Java解法

    https://leetcode-cn.com/problems/factorial-trailing-zeroes/ 172. 阶乘后的零 这题要完成其实要知道一个很巧妙的思想,就是阶乘里面,后面的 ...

  6. 【iOS】PrefixHeader.pch

    还不太理解,暂且记下.

  7. Something wrong with EnCase v8 index search results

    My friend told me that she installed EnCase v8.05 on her workstation which OS version is Win 10. She ...

  8. KD-tree 专题「Hide and Seek · 巧克力王国」

    Lockey的瞎理解 抄了一遍板子又水了俩题,感觉对KD-tree 稍稍理解了一点儿,唠叨一下(二维的KD-tree),如有错误请指出(Lockey 洗脸恭听) 普通平衡树维护的是一维的序列,但对于二 ...

  9. 深入理解JVM-java字节码文件结构剖析(练习解读字节码)

    public class MyTest2 { String str = "Welcome"; private int x = 5; public static Integer in ...

  10. Selenium模拟登陆百度贴吧

    Selenium模拟登陆百度贴吧 from selenium import webdriver from time import sleep from selenium.webdriver.commo ...