平衡二叉树

平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

平衡因子

某结点的左子树与右子树的高度(深度)差即为该结点的平衡因子(BF,Balance Factor)。平衡二叉树上所有结点的平衡因子只可能是 -1,0 或 1。如果某一结点的平衡因子绝对值大于1则说明此树不是平衡二叉树。为了方便计算每一结点的平衡因子我们可以为每个节点赋予height这一属性,表示此节点的高度。

基础设计

首先我们可以设计出AVL树节点,并且实现一些简单通用的方法供后续操作。

/*** AVLTree是BST,所以节点值必须是可比较的*/
public class AvlTree<E extends Comparable<E>>{private class Node{public E e;public Node left;public Node right;public int height;public Node(E e){this.e = e;this.left = null;this.right = null;this.height = 1;}}private Node root;private int size;public AvlTree(){root=null;size=0;}//获取某一结点的高度private int getHeight(Node node){if(node==null){return 0;}return node.height;}public int getSize(){return size;}public boolean isEmpty(){return size == 0;}/*** 获取节点的平衡因子* @param node* @return*/private int getBalanceFactor(Node node){if(node==null){return 0;}return getHeight(node.left)-getHeight(node.right);}//判断树是否为平衡二叉树public boolean isBalanced(){return isBalanced(root);}private boolean isBalanced(Node node){if(node==null){return true;}int balanceFactory = Math.abs(getBalanceFactor(node));if(balanceFactory>1){return false;}return isBalanced(node.left)&&isBalanced(node.right);}
}

添加节点

往平衡二叉树中添加节点很可能会导致二叉树失去平衡,所以我们需要在每次插入节点后进行平衡的维护操作。插入节点破坏平衡性有如下四种情况:

LL(右旋)

LL的意思是向左子树(L)的左孩子(L)中插入新节点后导致不平衡,这种情况下需要右旋操作,而不是说LL的意思是右旋,后面的也是一样。

我们将这种情况抽象出来,得到下图:

我们需要对节点y进行平衡的维护。步骤如下图所示:

/*** 右旋转*/
private Node rightRotate(Node y){Node x = y.left;Node t3 = x.right;x.right = y;y.left = t3;//更新heighty.height = Math.max(getHeight(y.left),getHeight(y.right))+1;x.height = Math.max(getHeight(x.left),getHeight(x.right))+1;return x;
}

RR


我们将这种情况抽象出来,得到下图:

我们需要对节点y进行平衡的维护。步骤如下图所示:

/*** 左旋转*/
private Node leftRotate(Node y){Node x = y.right;Node t2 = x.left;x.left = y;y.right = t2;//更新heighty.height = Math.max(getHeight(y.left),getHeight(y.right))+1;x.height = Math.max(getHeight(x.left),getHeight(x.right))+1;return x;
}

LR


我们将这种情况抽象出来,得到下图:

我们需要对节点y进行平衡的维护。步骤如下图所示:

第三个图中x和z反了,失误

RL


我们将这种情况抽象出来,得到下图:

我们需要对节点y进行平衡的维护。步骤如下图所示:

第二个图中y的左孩子为T1,第三个图中x和z反了,孩子也错了,应该是从左至右T1,T2,T3,T4,失误。。。

添加节点代码

// 向二分搜索树中添加新的元素(key, value)
public void add(E e){root = add(root, e);
}// 向以node为根的二分搜索树中插入元素(key, value),递归算法
// 返回插入新节点后二分搜索树的根
private Node add(Node node, E e){if(node == null){size ++;return new Node(e);}if(e.compareTo(node.e) < 0)node.left = add(node.left, e);else if(e.compareTo(node.e) > 0)node.right = add(node.right, e);//更新heightnode.height = 1+Math.max(getHeight(node.left),getHeight(node.right));//计算平衡因子int balanceFactor = getBalanceFactor(node);if(balanceFactor > 1 && getBalanceFactor(node.left)>0) {//右旋LLreturn rightRotate(node);}if(balanceFactor < -1 && getBalanceFactor(node.right)<0) {//左旋RRreturn leftRotate(node);}//LRif(balanceFactor > 1 && getBalanceFactor(node.left) < 0){node.left = leftRotate(node.left);return rightRotate(node);}//RLif(balanceFactor < -1 && getBalanceFactor(node.right) > 0){node.right = rightRotate(node.right);return leftRotate(node);}return node;
}

删除节点

在删除AVL树节点前需要知道二分搜索树的节点删除操作【点此学习吧!】,和二分搜索树删除节点不同的是我们删除AVL树的节点后需要进行平衡的维护操作。

public E remove(E e){Node node = getNode(root, e);if(node != null){root = remove(root, e);return node.e;}return null;
}private Node remove(Node node, E e){if( node == null )return null;Node retNode;if( e.compareTo(node.e) < 0 ){node.left = remove(node.left , e);retNode = node;}else if(e.compareTo(node.e) > 0 ){node.right = remove(node.right, e);retNode = node;}else{   // e.compareTo(node.e) == 0// 待删除节点左子树为空的情况if(node.left == null){Node rightNode = node.right;node.right = null;size --;retNode = rightNode;}// 待删除节点右子树为空的情况else if(node.right == null){Node leftNode = node.left;node.left = null;size --;retNode = leftNode;}else {// 待删除节点左右子树均不为空的情况// 找到比待删除节点大的最小节点, 即待删除节点右子树的最小节点// 用这个节点顶替待删除节点的位置Node successor = minimum(node.right);successor.right = remove(node.right, successor.e);successor.left = node.left;node.left = node.right = null;retNode = successor;}}if(retNode==null)return null;//维护平衡//更新heightretNode.height = 1+Math.max(getHeight(retNode.left),getHeight(retNode.right));//计算平衡因子int balanceFactor = getBalanceFactor(retNode);if(balanceFactor > 1 && getBalanceFactor(retNode.left)>=0) {//右旋LLreturn rightRotate(retNode);}if(balanceFactor < -1 && getBalanceFactor(retNode.right)<=0) {//左旋RRreturn leftRotate(retNode);}//LRif(balanceFactor > 1 && getBalanceFactor(retNode.left) < 0){node.left = leftRotate(retNode.left);return rightRotate(retNode);}//RLif(balanceFactor < -1 && getBalanceFactor(retNode.right) > 0){node.right = rightRotate(retNode.right);return leftRotate(retNode);}return retNode;
}

详细图文——AVL树相关推荐

  1. 史上最详细的AVL树的实现(万字+动图讲解旋转)

           

  2. 种树:二叉树、二叉搜索树、AVL树、红黑树、哈夫曼树、B树、树与森林

    虽然今天不是植树节,但是我今天想种树. 文章目录 树,什么是树? 二叉树 定义 二叉树的创建 二叉树的前中后序遍历 前序遍历: 中序遍历 后序遍历 已知前序.中序遍历结果,还原二叉树 已知后序.中序遍 ...

  3. AVL树的实现(图文详解)

    AVL树的实现 AVL树定义 AVL树其实就是一棵特殊的二叉树,为什么会出现AVL树,AVL树比普通二叉树优势在什么地方呢? 我们知道,一棵普通的二叉搜索树,以其特殊的性质(左<根<右), ...

  4. 20分钟搞定平衡二叉树(AVL树)【超详细】

    文章目录 一.树结构入门 1.什么是树? 2.树结构常用术语 3.二叉搜索树 二.平衡二叉树(AVL树) 1. AVL树简介 2. 失衡二叉排序树的分析与调整 3. 为什么有了平衡树还需要红黑树? 一 ...

  5. 二叉平衡树(AVL树)详细理解

    二叉平衡树(AVL树) AVL树插入元素结论 单旋转: 双旋转: 如果看到后面会发现,我下面举得列子,类型一和类型三和我结论里面的有点不一样,那是因为类型一的节点4和类型三的节点14无论以何种方式都能 ...

  6. AVL树添加节点后的平衡操作(一)逻辑分析:左旋、右旋、双旋(超详细图解)

    AVL树 AVL树是最早发明的自平衡二叉搜索树之一,其名字来源于两位发明它的科学家G. M. Adelson-Velsky 和 E. M. Landis(来自苏联的科学家). AVL树的特点 AVL树 ...

  7. 算法小讲堂之平衡二叉树|AVL树(超详细~)

    文章目录 一.前言 二.定义 三.原理 3.1 查找操作 3.2 最小(大)值结点 3.3 旋转操作 3.3.1 LL旋转 3.3.2 RR旋转 3.3.3 LR旋转 3.3.4 RL旋转 3.4 插 ...

  8. AVL树(二)之 C++的实现

    AVL树(二)之 C++的实现 概要 上一章通过C语言实现了AVL树,本章将介绍AVL树的C++版本,算法与C语言版本的一样. 目录 1. AVL树的介绍 2. AVL树的C++实现 转载请注明出处: ...

  9. AVL树(一)之 C语言的实现

    概要 本章介绍AVL树.和前面介绍"二叉查找树"的流程一样,本章先对AVL树的理论知识进行简单介绍,然后给出C语言的实现.本篇实现的二叉查找树是C语言版的,后面章节再分别给出C++ ...

  10. 数据结构与算法——AVL树类的C++实现

    关于AVL树的简单介绍能够參考: 数据结构与算法--AVL树简单介绍 关于二叉搜索树(也称为二叉查找树)能够參考:数据结构与算法--二叉查找树类的C++实现 AVL-tree是一个"加上了额 ...

最新文章

  1. excel数据库_将excel文件导入mysql数据库教程(PHP实现)
  2. 二次优化问题dfp_优化设计-fmincon函数介绍-序列二次的规划(SQP)-subspacetrustregion-activesett.pdf...
  3. matlab文件批量导入问题总结
  4. 如何加快Json 序列化?有哪些方法?
  5. python 微信bot_我如何创建Python Bot自动登录到强制门户
  6. cisco 2801 配置voip
  7. 介绍一个不错的图书下载网站-顺便推荐几本书
  8. [UOJ455][UER #8]雪灾与外卖——堆+模拟费用流
  9. python基础系列教程——Python3.x标准模块库目录
  10. Linux核心应用命令速查
  11. 【监控笔记】【2.2】扩展事件——死锁监控
  12. 企业微信支付提示请在微信客户端打开链接_微信h5支付?
  13. VS2013 community 官方版下载
  14. Commit cannot be completed since the group has already rebalanced and assign
  15. 读LockSupport源码
  16. 软考数据库考试有题库吗_网络工程师真的像大家说的那么容易考吗?
  17. Excel表格转换为MarkDown表格工具
  18. Qt的TQTreeWidget控件
  19. border:none以及border:0的区别
  20. Linux驱动学习之什么是驱动?

热门文章

  1. 警告提示:Capturing ‘self‘ strongly in this block is likely to lead to a retain cycle
  2. linux根目录不足,追加空间到根目录
  3. 点击唤起电话功能和企业微信聊天窗口事件(H5)
  4. Integrated Electrical Test Vehicle Co-designed with Microfluidics for Evaluating the Performance of
  5. 已是操作系统的一部分_什么是操作系统 第2部分
  6. 免Flash文件上传 (Upload without Flash)
  7. 2018年3大UI设计趋势,你知道吗?
  8. JS 案例 树形菜单
  9. slf4j日志门面担当
  10. Swarm and shipyard