AVL树
平衡因子:某节点的左右子树高度差。
特点
- 每个叶子结点的平衡因子只能是1,0,-1,如果超过1代表失衡。
- 每个节点的左右子树高度差不超过1
- 搜索,添加,删除的时间复杂度是O(logn)
上图的不是AVL树,AVL树是平衡二叉搜索树的一种实现,平衡二叉搜索树的实现有AVL树和红黑树。
他们都能在添加删除之后都能自己调整到平衡状态。
左旋操作(RR)
g.right=p.left;
p.left=g;
让p变成这棵树的根节点。
在操作的时候注意发生parent属性改变的节点。(T1,p,g)
右旋操作(LL)
g.left=p.right;
p.right=g;
protected static class Node<E>{
E element;
Node<E> left;
Node<E> right;
Node<E> parent;
public Node(E element,Node<E> parent){
this.element = element;
this.parent = parent;
}
}
private static class AVLNode<E> extends Node<E>{
public AVLNode(){
super(element,parent);
}
int height=1;
private int balanceFactor(){
int leftHeghit = left==null?0:((AVLNode<E>)left).height;
int rightHeghit = right==null?0:((AVLNode<E>)right).height;
}
}
//判断是否平衡,平衡因子绝对值小于等于1代表平衡
private boolean isBalanced(Node node){
return Math.abs(((AVLNode<E>)node).balanceFactor)<=1;
}
//添加之后恢复平衡
protected void afterAdd(Node<E> node){
while((node=node.parent)!=null){
if(isBalanced(node)){
//如果平衡,更新节点的高度
updateHeight(node);
}else{
//恢复平衡
reblanced(node);
break;
}
}
}
private void reblanced(Node<E> grand){
Node<E> parent = ((AVLNode<E>)grand).tallerChild();
Node<E> node = ((AVLNode<E>)parent).tallerChild();
if(parent.isLeftChild()){
if(node.isLeftChild()){ //LL
//右旋
rotateRight(grand);
}else{//LR
//左旋
rotateLeft(parent);
//右旋
rotateRight(grand);
}
}else{
if(node.isLeftChild()){ //RL
//右旋
rotateRight(parent);
//左旋
rotateLeft(grand);
}else{//RR
//右旋
rotateRight(grand);
}
}
}
//左旋
private void rotateLeft(Node<E> grand){
Node<E> parent = grand.right;
Node<E> child = parent.left;
grand.right = child;
parent.left = grand;
//让parent变成子树的根节点
parent.parent = grand.parent;
if(grand.isLeftChild()){
grand.parent.left = parent;
}else if(grand.isRightChild()){
grand.parent.right=parent;
}else{
//grand是根节点
root = parent;
}
//更新child的parent
if(child!=null){
child.parent = grand;
}
//更新grand 的parent
grand.parent = parent;
//更新parent和grand的高度
updateHeight(parent);
updateHeight(grand);
}
//右旋
private void rotateRight(Node<E> grand){
Node<E> parent = grand.right;
Node<E> child = parent.left;
grand.left = child;
parent.right = grand;
//剩下的步骤和左旋一样,更新三者的parent,更新高度,因此抽取共有部分
afterRotate(grand,parent,child);
}
private void afterRotate(Node<E> grand,Node<E> parent,Node<E> child){
//让parent变成子树的根节点
parent.parent = grand.parent;
if(grand.isLeftChild()){
grand.parent.left = parent;
}else if(grand.isRightChild()){
grand.parent.right=parent;
}else{
//grand是根节点
root = parent;
}
//更新child的parent
if(child!=null){
child.parent = grand;
}
//更新grand 的parent
grand.parent = parent;
//更新parent和grand的高度
updateHeight(parent);
updateHeight(grand);
}
//更新高度就是将当前高度+1,当前高度就是左右子树较大的高度
private void updateHeight(){
int leftHeghit = left==null?0:((AVLNode<E>)left).height;
int rightHeghit = right==null?0:((AVLNode<E>)right).height;
this.height = Math.max(leftHeight,rightHeight)+1;
}
//删除节点后调整二叉搜索树的平衡
public void afterRemove(Node<E> node){
while((node=node.parent)!=null){
if(isBalanced(node)){
//如果平衡,更新节点的高度
updateHeight(node);
}else{
//恢复平衡
reblanced(node);
}
}
}
public void remove(E element){
remove(node(element));
}
AVL树添加节点时可能会导致所有祖先节点都失衡。
只要让高度最低的失衡节点恢复平衡,整棵树就会恢复平衡。O(1)
AVL树删除操作可能导致父节点或祖先节点失衡(只有一个),让父节点恢复平衡后,可能导致更高层的祖先节点失衡。最多需要O(logn)次调整。
平均时间复杂度
搜索:O(logn)
添加:O(logn),仅需要O(1)常数级别的操作
删除:O(logn),最多需要logn次旋转
先左旋后右旋 LR操作
先对P进行左旋,再对g进行右旋
RL操作,先对p进行右旋转,再对g进行左旋转。