平衡二叉树(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树。代码里重点就是插入和删除怎样去维护平衡。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
本文来自博客园,作者:|旧市拾荒|,转载请注明原文链接:https://www.cnblogs.com/xiaoyh/p/10401543.html