平衡二叉树(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树。维护平衡只需在插入和删除时维护平衡即可。

    《平衡二叉树(AVL)介绍及其实现》

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

    《平衡二叉树(AVL)介绍及其实现》

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

    《平衡二叉树(AVL)介绍及其实现》

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

   《平衡二叉树(AVL)介绍及其实现》

二、代码实现

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

《平衡二叉树(AVL)介绍及其实现》
《平衡二叉树(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

 

    原文作者:|旧市拾荒|
    原文地址: https://www.cnblogs.com/xiaoyh/p/10401543.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞