在 算法系列(八)数据结构之二叉查找树 中,介绍了二叉查找树的定义和基本操作。大部分操作的平均时间复杂度为O(logN),但是如果预先输入的数据有序,那么一连串的insert操作花费的时间就会很长,时间复杂度为O(N),一种解决方法是增加平衡附加条件,使得任何节点深度都不会过深。AVL树是最先发明的自平衡二叉查找树。
PS:写avl的时候突然发现之前的一个问题,将树的节点暴露了出去,这样不能保证平衡条件不被改变。github上的代码已经做了修改。外部不能直接访问TreeNode
概述:
在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 "An algorithm for the organization of information" 中发表它。
定义和特性:
一棵AVL树是其每个节点的左子树和右子树的高度最多差1的二叉查找树。
高度为 h 的 AVL 树,节点数 N 最多2^h − 1; 最少N(h)=N(h− 1) +N(h− 2) + 1。
最少节点数
N(0) = 0 (表示 AVL Tree 高度为0的节点总数)
N(1) = 1 (表示 AVL Tree 高度为1的节点总数)
N(2) = 2 (表示 AVL Tree 高度为2的节点总数)
插入操作
单旋转


双旋转

代码实现
package com.algorithm.tree;
import java.util.Comparator;
/**
* AVL树
*
* @author chao
*
* @param <T>
*/
public class AVLTree<T> extends BinarySeachTree<T> {
public AVLTree(T root) {
super(root);
}
public AVLTree(T root, Comparator<T> comparator) {
super(root, comparator);
}
@Override
protected BinaryTreeNode<T> insert(BinaryTreeNode<T> cur, BinaryTreeNode<T> x) {
if (cur == null) {
return x;
}
int compareresult = compare(cur, x);
if (compareresult < 0) {
cur.right = insert(cur.right, x);
if (getHeight(cur.right) - getHeight(cur.left) == 2) {
if (compare(x, cur.right) > 0) {
cur = roateWithRightChild(cur);
} else {
cur = doubleWithRightChild(cur);
}
}
} else if (compareresult > 0) {
cur.left = insert(cur.left, x);
if (getHeight(cur.left) - getHeight(cur.right) == 2) {
if (compare(x, cur.left) < 0) {
cur = roateWithLeftChild(cur);
} else {
cur = doubleWithLeftChild(cur);
}
}
} else {
cur.hintcount++;
}
return cur;
}
/**
* 左子树单旋转
*
* @param node
* @return
*/
protected BinaryTreeNode<T> roateWithLeftChild(BinaryTreeNode<T> k2) {
BinaryTreeNode<T> k1 = k2.left;
k2.left = k1.right;
k1.right = k2;
return k1;
}
/**
* 右子树单旋转
*
* @param node
* @return
*/
protected BinaryTreeNode<T> roateWithRightChild(BinaryTreeNode<T> k2) {
BinaryTreeNode<T> k1 = k2.right;
k2.right = k1.left;
k1.left = k2;
return k1;
}
/**
* 左子树双旋转
*
* @param node
* @return
*/
protected BinaryTreeNode<T> doubleWithLeftChild(BinaryTreeNode<T> k3) {
k3.left = roateWithRightChild(k3.left);
return roateWithLeftChild(k3);
}
/**
* 右子树双旋转
*
* @param node
* @return
*/
protected BinaryTreeNode<T> doubleWithRightChild(BinaryTreeNode<T> k3) {
k3.right = roateWithLeftChild(k3.right);
return roateWithRightChild(k3);
}
}
@Override
public void remove(T x) {
BinaryTreeNode<T> node = findNode(root, x);
if (node == null || node.hintcount < 0) {
return;
} else {
node.hintcount--;
}
}
欢迎扫描二维码,关注公众账号
