一、什么是AVL树
- AVL树我们可以看作BST树的一个特殊情况。AVL树就是对BST树失衡的节点用旋转的方式让它达到平衡状态
- 什么情况下为失衡?
AVL树要求:任一节点,它的左右子树高度差不超过 1 ,那就是我们对失衡节点通过旋转让它平衡就好
例如上图:5 这个节点右子树高度为2,左子树高度为0,所以这个节点就失衡了。如果我们还是用BST树的方式去存储,效率很低,因为5-6-7构成了单链表。
二、创建AVL类和节点类
public class AVLtree<T extends Comparable> {
private Entry<T> root;//根节点
/**
*AVL树的初始化
*/
public AVLtree(Entry<T> root) {
this.root = null;
}
static class Entry<E>{
private E value;//数据域
private Entry<E> left;//左孩子域
private Entry<E> right;//右孩域
private int hight;//树的高度
public Entry(E value, Entry<E> left, Entry<E> right, int hight) {
this.value = value;
this.left = left;
this.right = right;
this.hight = hight;
}
public Entry() {
this(null,null,null,1);
}
public Entry(E value) {
this(value,null,null,1);
}
}
三、四种旋转方式
在此之前我们要创建一个可以返回节点高度的函数:
/**
* 返回最大高度
* @param left
* @param right
* @return
*/
public int maxHeight(Entry<T> left,Entry<T> right){
return height(left)>height(right)? height(left):height(right);
}
/**
*返回节点高度值
* @param node
* @return
*/
private int height(Entry<T> node) {
return node==null? 0:node.hight;
}
一、左旋转
/**
* 以node进行左旋转 节点失衡(右孩子的右支树太高)
* @param node
* @return child 返回的新根节点
*/
public Entry<T> leftRotate(Entry<T>node){
Entry child = node.right;
node.right = child.left;
child.left = node;
node.hight = maxHeight(node.left,node.right)+1;
child.hight = maxHeight(child.left,child.right)+1;
return child;
}
二、右旋转
/**
* 以node为根节点进行右旋转操作(左孩子的左支树太高)
* @param node
* @return child 返回新的根节点
*/
public Entry<T> rightRotate(Entry<T>node){
Entry child = node.left;
node.left = child.right;
child.right = node;
node.hight = maxHeight(node.left,node.right)+1;
child.hight = maxHeight(child.left,child.right)+1;
return child;
}
三、左-右旋转
/**
* 左-右 旋转 左孩子的右子树太高了
*/
public Entry<T> leftBalance(Entry<T> node){
node.left=leftRotate(node.left);
return rightRotate(node);
}
四、右-左旋转
/**
* 右-左 旋转 右孩子的左子树太高了
*/
public Entry<T> rightBalance(Entry<T> node){
node.right=leftRotate(node.right);
return leftRotate(node);
}
四、AVL树的插入删除
插入:
/**
*AVL树的插入 (就是在BST树节点插入后加上判断条件就好)
* @param value 插入的节点值
*/
public void insert(T value) {
root = insert(root,value );
}
public Entry<T> insert(Entry<T> root, T value){
if (root == null){
root = new Entry<>(value);
}
if (root.value.compareTo(value)>0){
root.left = insert(root.left,value);
//判断root节点是否失衡
if (height(root.left)-height(root.right)>1){
if (height(root.left.left)>height(root.left.right)){
//左孩子的右子树太高
root = rightRotate(root);
}else {
//左孩子的左子树太高了
root = leftBalance(root);
}
}
}else if (root.value.compareTo(value)<0){
root.right = insert(root.right,value);
//判断root节点是否失衡
if (height(root.right)-height(root.left)>1){
if (height(root.right.right)>height(root.right.left)){
//右孩子的左子树太高
root = leftRotate(root);
}else {
//右孩子的右子树太高
root = rightBalance(root);
}
}
}
root.hight = maxHeight(root.left,root.right)+1;
return root;
}
删除:
/**
* AVL树的删除
* @param
*/
public void remove(T value){
root = remove(root,value);
}
public Entry<T> remove(Entry<T> root,T value){
if (root==null){
return null;
}
if (root.value.compareTo(value)>0){
//当前节点的值比待删节点的值大,则继续在左子树中寻找
root.left = remove(root.left,value);
if (height(root.right)-height(root.left)>1){
if (height(root.right.right)>height(root.right.left)){
//右孩子的左子树太高
root = leftRotate(root);
}else {
//右孩子的右子树太高
root = rightBalance(root);
}
}
}else if (root.value.compareTo(value)<0){
//当前节点的值比待删节点的值小,则继续在右子树中寻找
root.right = remove(root.right,value);
//判断root节点是否失衡
if (height(root.left)-height(root.right)>1){
if (height(root.left.left)>height(root.left.right)){
//左孩子的右子树太高
root = rightRotate(root);
}else {
//左孩子的左子树太高了
root = leftBalance(root);
}
}
}else {
//已找到待删除节点root,考虑有两个孩子的情况(为了不让产生旋操作,哪边高删除那边)
if (root.right!=null && root.left!=null){
if (height(root.left)>=height(root.right)){
//标记待删除节点的前驱节点,(左子树最大节点)
Entry<T> pre = root.left;
while (pre.right != null) {
//使pre指向待删节点的前驱节点
pre = pre.right;
}
root.value = pre.value;
//继续递归删除节点的前驱节点
root.left = remove(root.left, pre.value);
}else {//删除节点的后驱(右子树最小的那个节点)
Entry<T> bre = root.right;
while (bre.right != null) {
//使bre指向待删节点的后驱节点
bre = bre.left;
}
root.value = bre.value;
//继续递归删除节点的后驱节点
root.right = remove(root.left, bre.value);
}
}else {
if (root.left!=null){
return root.left;
}else if (root.right!=null){
return root.right;
}else {
return null;
}
}
}
root.hight = maxHeight(root.left,root.right)+1;
return root;
}