zoukankan      html  css  js  c++  java
  • 平衡二叉树(AVL)介绍及其实现

    一、平衡二叉树

      任何一个数据的查找过程都需要从根结点出发,沿某一个路径朝叶子结点前进。因此查找中数据比较次数与树的形态密切相关。 对于二叉树来说,当树中每个结点左右子树高度大致相同时,树高为logN。则平均查找长度与logN成正比,查找的平均时间复杂度在O(logN)数量级上。当先后插入的关键字有序时,BST退化成单支树结构。此时树高n。平均查找长度为(n+1)/2,查找的平均时间复杂度在O(N)数量级上。

      二叉查找树在最差情况下竟然和顺序查找效率相当,这是无法仍受的。事实也证明,当存储数据足够大的时候,树的结构对某些关键字的查找效率影响很大。当然,造成这种情况的主要原因就是BST不够平衡(左右子树高度差太大)。既然如此,那么我们就需要通过一定的算法,将不平衡树改变成平衡树。因此,AVL树就诞生了。AVL(Adelson-Velskii and Landis)树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文《An algorithm for the organization of information》中发表了它 。

      在二叉树中,任何一个节点v的平衡因子都定义为其左、右子树的高度差。空树的高度定义为-1。在二叉查找树T中,若所有节点的平衡因子的绝对值均不超过1,则称T为一棵AVL树。维护平衡只需在插入和删除时维护平衡即可。

        

      新节点记为N,第一个被破坏平衡的祖先记为p(至少是祖父),在同一路径上的p的子节点记为q,q的子节点记为s。按pqs的位置关系分为左左型,左右型,右右型,右左型,两两对称。通过旋转来使树重新平衡,旋转不会破坏BST的性质,也就是中序遍历的顺序,但能改变子树高度。

        

      旋转操作:旋转操作是一种调整树结构而不改变二叉查找树特性的手段。这里要理解树旋转的意义,树的最终目的不是维护节点与节点之间的层级关系,关键是如何用AVL树这种数据结构进行更好的查找和搜索。

        

      先看中间,左左型和右右型,它们只需沿反方向旋转一次即可。左右型和右左型,先调整q和s,转变为上述两种类型。念一下中序遍历顺序,找找感觉。

       

    二、代码实现

      AVL树是一棵二叉查找树,与普通二叉查找树不同的是,在插入和删除节点之后需要重新进行平衡,因此继承并重写普通二叉查找树的insert和remove方法,就可以实现一棵AVL树。代码里重点就是插入和删除怎样去维护平衡。

      1 // 涉及到的类前面博客都有
      2 public class AVLTree<K, V> extends BinarySearchTree<K, V> implements IBinarySearchTree<K, V> {
      3     @Override
      4     public BSTNode<K, V> insert(K key, V value) {
      5         // 先按bst的方式来插入,再调整
      6         BSTNode<K, V> nnode = super.insert(key, value);
      7         // 向上找到第一个不平衡的祖先p
      8         BSTNode<K, V>[] pqs = firstUnbalance(nnode);
      9         if (null != pqs) {// 不平衡
     10             // System.out.println(pqs[0].key);
     11             reBalance(pqs);
     12         }
     13         return nnode;
     14     }
     15 
     16     /* 分pqs的形状,来调用左旋和右旋 */
     17     private void reBalance(BSTNode<K, V>[] pqs) {
     18         if (pqs == null)
     19             return;
     20         BSTNode p = pqs[0];// 不平衡的那个祖先
     21         BSTNode q = pqs[1];// p的子节点
     22         BSTNode s = pqs[2];// q的子节点
     23 
     24         if (q.isRight() && s.isRight()) {// 右右型,以p为中心逆时针旋转
     25             leftRotate(p, q);  // 方法在前面的博客
     26             // reBalance(firstUnbalance(q));
     27         } else if (q.isLeft() && s.isLeft()) {// 左左型,以p为中心顺时针旋转
     28             rightRotate(p, q);
     29             // reBalance(firstUnbalance(q));
     30         } else if (q.isLeft() && s.isRight()) {// 左右型
     31             // q.right = s.left;
     32             // if (s.left != null) {
     33             // s.left.parent = q;
     34             // s.left.isLeftChild = false;
     35             // }
     36             // q.parent = s;
     37             // s.left = q;
     38             // q.isLeftChild = true;
     39             //
     40             // s.parent = p;
     41             // p.left = s;
     42             // s.isLeftChild = true;
     43             leftRotate(q, s);// q,s左旋,变为左左型
     44             rightRotate(p, s);
     45             // reBalance(firstUnbalance(s));
     46         } else {// 右左型
     47             // q.left = s.right;
     48             // if (s.right != null) {
     49             // s.right.parent = q;
     50             // s.right.isLeftChild = true;
     51             // }
     52             // q.parent = s;
     53             // s.right = q;
     54             // q.isLeftChild = false;
     55             //
     56             // s.parent = p;
     57             // p.right = s;
     58             // s.isLeftChild = false;
     59             rightRotate(q, s);
     60             leftRotate(p, s);
     61             // reBalance(firstUnbalance(s));
     62         }
     63     }
     64 
     65     private BSTNode<K, V>[] firstUnbalance(BSTNode<K, V> n) {
     66         if (n == null)
     67             return null;
     68         BSTNode s = n;
     69         BSTNode p = n.parent;
     70         if (p == null)
     71             return null;
     72         BSTNode g = p.parent;
     73         if (g == null)
     74             return null;
     75         if (unBalance(g)) {// 不平衡了
     76             return new BSTNode[] { g, p, s };
     77         } else {
     78             return firstUnbalance(p);
     79         }
     80 
     81     }
     82 
     83     @Override
     84     public void remove(K key) {
     85         BSTNode<K, V> node = super.lookupNode(key);
     86         if (node == null)
     87             return;
     88 
     89         BSTNode<K, V> parent = node.parent;
     90         BSTNode<K, V> left = node.left;
     91         BSTNode<K, V> right = node.right;
     92 
     93         if (left == null && right == null) {// leaf node
     94             super.removeNode(node);
     95             reBalance(parent);    // 重新平衡
     96         } else if (right == null) {// has only left child.左孩子替换自身
     97             // if (node.isLeft()) {
     98             // parent.left = left;
     99             // left.parent = parent;
    100             // } else {
    101             // if (parent == null) {// node is root
    102             // left.parent = null;
    103             // root = left;
    104             // } else {
    105             // parent.right = left;
    106             // left.isLeftChild = false;
    107             // left.parent = parent;
    108             // }
    109             // }
    110             BSTNode<K, V> predecessor = maxNode(left);
    111             BSTNode<K, V> parentOfPredecessor = predecessor.parent;
    112             super.removeNode(predecessor);
    113             node.key = predecessor.key;
    114             node.value = predecessor.value;
    115             reBalance(parentOfPredecessor);
    116 
    117         } else {// 有右孩子,找到右子树的最小
    118             BSTNode<K, V> successor = minNode(right);
    119             BSTNode<K, V> parentOfSuccessor = successor.parent;
    120             // minNode must be leaf node
    121             super.removeNode(successor);
    122             node.key = successor.key;
    123             reBalance(parentOfSuccessor);
    124         }
    125     }
    126 
    127     private void reBalance(BSTNode<K, V> node) {
    128         if (node == null)
    129             return;
    130 
    131         BSTNode<K, V> right = node.right;
    132         BSTNode<K, V> left = node.left;
    133         int hOfRight = getHeight(right);
    134         int hOfleft = getHeight(left);
    135 
    136         if (hOfRight - hOfleft >= 2) {// 右侧高
    137             leftRotate(node, right);// 左旋
    138             reBalance(right);
    139         } else if (hOfRight - hOfleft <= -2) {
    140             rightRotate(node, left);
    141             reBalance(left);
    142         } else {
    143             reBalance(node.parent);
    144         }
    145     }
    146 }
    View Code
  • 相关阅读:
    HTML中一定会常用的标签和标签属性(这是网页构成的重要元素
    HTML(超文本语言)
    SQL SERVER中视图、事务
    important覆盖行内样式
    线性渐变
    「JavaScript面向对象编程指南」闭包
    移动端文章图片大小限制
    Vue中ajax返回的结果赋值
    「JavaScript面向对象编程指南」基础
    JS媒体查询
  • 原文地址:https://www.cnblogs.com/xiaoyh/p/10401543.html
Copyright © 2011-2022 走看看