数据结构:平衡二叉树
在学习平衡二叉树之前,我们需要先对二叉查找树进行一定的了解,其特征是:查找的性能取决于树的形状。因此在某些极端情况下,二叉查找树会退化为一个线性链表,查找效率的时间复杂度从O(log2n)降到了O(n)。为了规避这个缺点,引入了平衡二叉树。可以理解为平衡二叉树是基于二叉查找树的优化。
平衡二叉树在二叉查找树的基础之上增加了一个新的特性:每一个节点的左子树与右子树高度相差最多为1,这个高度的限制就可以避免出现树结构退化为线性链表的情况。因此,即便是在最坏情况下,平衡二叉树的查找,插入,删除时间复杂度都为O(log2n)。
实现原理
在了解了平衡二叉树大致的概念后,再看一下它具体实现的方式吧(゜▽゜*)
既然是要求每一个节点的左子树与右子树高度相差最多为1,那么就可以对节点对象引入一个属性值进行判断,这个属性值也就是平衡因子,其值为节点的左子树深度 - 右子树深度。在构建一棵平衡二叉树时,每当插入一个新的节点,都需要检查插入后是否破坏了树的平衡,如果失衡,那么则需要通过旋转去改变树的结构,使其再次平衡。
可以说旋转是平衡二叉树的核心,也是相对来说比较难懂的概念了,当然难懂只是针对于我这种空间想象能力比较差的( ′⌒`)
当然旋转也分几种情况,下面通过图片进行每种情况的示例:
旋转
①在节点X的左孩子节点的左子树中插入了新的元素(简称左左)
如图,在节点9的左孩子5的左子树3插入了新的节点2,可以判断出节点9为失衡节点。
此时我们对失衡节点9进行一次以轴为节点5的右旋转,该树再次恢复了平衡。
代码实现
可以观察到,节点8从节点5的右孩子变为了节点9的左孩子,节点5从节点9的左孩子变为了9的父节点。
那么我们可以对此进行代码描述
[code] private AVLNode<T> rotateRight(AVLNode<T> x){ //w节点为失衡节点x的左孩子 AVLNode<T> w = x.left; //1 失衡节点的左孩子变为w节点的右孩子 x.left=w.right; //2 w节点的右孩子变为失衡节点x w.right=x; //重新计算x节点和w节点的高度 x.height=Math.max(height(x.left),height(x.right))+1; w.height=Math.max(height(w.left),x.height)+1; return w;//返回新的根结点 }
②在节点X的右孩子节点的右子树中插入了元素(简称右右)
如图,在节点5的右孩子9的右子树11插入了新的节点14,可以判断出节点5为失衡节点。
此时我们对失衡节点5进行一次以轴为节点9的左旋转,该树再次恢复了平衡。
代码实现
可以观察到,节点7从节点9的左孩子变为了节点5的右孩子,节点9从节点5的右孩子变为了5的父节点。
不知道各位有没有发现,右右的情况完全是与左左相反的。
那么我们可以对此进行代码描述
[code] private AVLNode<T> rotateLeft(AVLNode<T> w){ //x为失衡结点w的右节点 AVLNode<T> x=w.right; //将失衡结点w的右子树变为x的左子树 w.right=x.left; //x的左子树变为失衡结点x x.left=w; //重新计算x w的高度 x.height=Math.max(height(x.left),w.height)+1; w.height=Math.max(height(w.left),height(w.right))+1; //返回新的根结点 return x; }
③在节点X的左孩子节点的右子树中插入了元素(简称左右)
该情况就稍微有些复杂了,我们仅通过一次旋转并不能获取到平衡的二叉树,此时需要先通过一次左旋转将其不稳定二叉树转换为左左的情况,再通过一次右旋转得到平衡二叉树。
如图,在节点15的左孩子6的右子树8插入了新的节点10,可以判断出节点15为失衡节点。
将节点6进行一次以8为轴的左旋转,此时得到我们之前分析的第①种情况:左左
此时再将节点15进行一次以8为轴的右旋转,该树再次恢复了平衡。
代码实现
可以观察到,在原树中插入了节点10以后,节点15变成了失衡节点,此时需要把节点8变为根节点才能重新恢复平衡。因此需要先对失衡节点的左孩子8进行左旋转,在对失衡节点15进行右旋转。
[code]private AVLNode<T> RotateLeftAndRight(AVLNode<T> x){ //x的左孩子先进行左旋转 x.left=singleRotateRight(x.left); //再进行x的右旋转 return singleRotateLeft(x); }
④在节点X的右孩子节点的左子树中插入了元素(简称右左)
与情况③互为镜像,此时需要先通过一次右旋转将其不稳定二叉树转换为右右的情况,再通过一次左旋转得到平衡二叉树。
如图,在节点8的右孩子15的左子树10插入了新的节点9,可以判断出节点8为失衡节点。
将节点10进行一次以15为轴的右旋转,此时得到我们之前分析的第②种情况:右右
此时再将结点8进行一次以10为轴的左旋转,该树再次恢复了平衡。
代码实现
与情况③互为镜像
[code]private AVLNode<T> rotateRightAndLeft(AVLNode<T> x){ //x的右孩子先进行右旋转 x.right=rotateRight(x.right); //再进行x的左旋转 return rotateLeft(x); }
- sdutacm-数据结构实验之查找二:平衡二叉树
- 数据结构实验之查找二:平衡二叉树---3374
- 数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)(转)
- SDUT 数据结构实验之查找二:平衡二叉树
- 数据结构——平衡二叉树
- 3374-数据结构实验之查找二:平衡二叉树
- 数据结构(scheme) -- 抽象数据类型(ADT) -- 平衡二叉树(AVL-Tree)
- 数据结构实验之查找二:平衡二叉树
- 数据结构实验之查找二:平衡二叉树
- 【数据结构】——平衡二叉树(插入)
- SDUT-3374 数据结构实验之查找二:平衡二叉树
- 数据结构—平衡二叉树
- [数据结构与算法]平衡二叉树实现
- 数据结构实验之查找二:平衡二叉树
- 数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)
- 数据结构—平衡二叉树
- 3374->数据结构实验之查找二:平衡二叉树
- 【数据结构与算法】数组和单链表转平衡二叉树
- 数据结构上机实验之二分查找之平衡二叉树
- java数据结构与算法之平衡二叉树(AVL树)的设计与实现