首先AVL树也叫二叉平衡树,AVL树一定是BST树,那么为什么要引入AVL树呢?它比BST树好在哪儿呢?
BST树:BST树的增删改查,是从根节点出发找到叶子节点再进行操作的,时间复杂度为O(logn)
那么问题来了,如果你要插入的数据构成一个等差数列的话,比如{1,3,5,7,9}
BST树将会变成一个链表:
这样的话它的时间复杂度岂不是退化成O(n)了?查找某个元素时得遍历链表。
AVL树:在BST树的基础上引入了平衡的概念,也就是每个节点的左右孩子高度差不超过1。
平衡后的上面的BST树将是这样子的(经过两次右旋操作,一会儿解释这几种旋转操作):
AVL树的节点类型定义:
static class Entry<T extends Comparable<T>>{
private T data;
private Entry<T> left;
private Entry<T> right;
private int high;//节点高度
public Entry(){
this(null,null,null,1);
}
public Entry(T data, int high) {
this(data,null,null,1);
}
public Entry(T data, Entry<T> left, Entry<T> right, int high) {
this.data = data;
this.left = left;
this.right = right;
this.high = high;
}
}
---------------------------------------------------------------------------------------------------------------------------------
下面来介绍这四种旋转操作以及适用情况:
①由于该节点的左孩子的左子树太高,引起的失衡,需要进行右旋操作:
文字不太好叙述,直接画个图来解释:
实现右旋的代码:
private Entry<T> rightRotate(Entry<T> node){
Entry<T> child = node.left;
node.left = child.right;
child.right=node;
//节点高度值更新
node.high = maxHeight(node.left,node.right)+1;//旋转以后node为孩子节点
child.high = maxHeight(child.left,child.right)+1;//旋转以后child为双亲节点
return child;
}
---------------------------------------------------------------------------------------------------------------------
②由于该节点的右孩子的右子树太高,引起的失衡,需要进行左旋操作:
实现左旋的代码:
private Entry<T> leftRotate(Entry<T> node){
//左旋转
Entry<T> child = node.right;
node.right = child.left;
child.left=node;
//节点高度值更新
node.high = maxHeight(node.left,node.right)+1;//旋转以后node为孩子节点
child.high = maxHeight(child.left,child.right)+1;//旋转以后child为双亲节点
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 = rightRotate(node.right); //先以右孩子为基准右旋转右子树
return leftRotate(node);//再以根节点为基准左旋转
}
---------------------------------------------------------------------------------------------------------------------
这四种旋转操作和AVL树的插入和删除操作息息相关,需要好好熟悉。