AVL树问题
06_AVL树
目录
1、AVL树
- 平衡因子(Balance Factor):某节点的左右子树的高度差
- AVL树的特点
- 每个节点的平衡因子只可能是1、0、-1(绝对值<=1,如果超过1,称之为“失衡”)
- 每个节点的左右子树高度差不超过1
- 搜索、添加、删除的时间复杂度是O(logn)
2、平衡对比
- 输入数据:35,37,34,56,25,62,57,9,74,32,94,80,75,100,16,82
3、简单的继承结构
3、AVL添加
3.1、添加导致的失衡
- 实例:往下面这棵子树中添加13
- 最坏情况:可能会导致所有祖先节点都失衡
- 父节点、非祖先节点,都不可能失衡
比如下图所示:
在这个树中添加元素13,那么会使父节点14失衡,祖父节点15和9都会失衡
3.1.1、LL—右旋转(单旋)
如下图所示:
我们在T0这个节点处添加一个节点的话,就会使g这个祖父节点失衡,由于n这个节点是g节点的左节点的左节点,即n = g.left.left,所以为LL,如果我们要使它变为一棵平衡二叉树,我们就需要将g节点向右旋转,使他变为p节点的子节点
也就是我们要做的操作就是:
- g.left = p.right
- p.right = g
然后我们要使p节点作为这个子树的根节点
同时我们还需要注意的是:我们还必须维护T2、p、g的parent属性,然后更新g,p的高度
3.1.2、RR—左旋转(单旋)
如下图所示:
我们要在T3节点处插入一个节点,那么就会导致祖父节点g失衡,由于n节点是祖父节点的右节点的右节点,也即n = g.right.right,所以为RR。我们要解决这个问题,只需要将这个树的g节点进行左旋就可以。
操作如下:
- g.right = p.right
- p.left = g
让p成为这棵子树的根节点
同时我们还需要注意的是:我们还得维护T1,p,g的parent属性,同时得先后更新g,p的高度。
3.1.3、LR—RR左旋转,LL右旋转(双旋)
如下图所示:
我们要在T2节点处添加新的节点,那么同样会导致g节点失衡,由于n = g.left.right,所以为LR,解决这种问题我们只要先对p节点进行左旋,然后对g节点进行右旋就可以解决问题
3.1.4、RL—LL右旋转,RR左旋转(双旋)
如下图所示:
我们要在T1节点处添加新的节点,那么同样会导致g节点失衡,由于n = g.right.left,所以为RL,解决这种问题我们只要先对p节点进行右旋,然后对g节点进行左旋就可以解决问题
如下即为左旋的代码:
/**
* 左旋转
*/
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节点
root = parent;
}
// 更新child的parent
if(child != null){
child.parent = grand;
}
// 更新grand的parent
grand.parent = parent;
// 更新高度
updateHeight(grand);
updateHeight(parent);
}
这里面的更新操作的代码其实很简单,只需要
public void updateHeight(){ // 更新高度
int leftHeight = left==null ? 0 : ((AVLNode<E>)left).height;
int rightHeight = right==null ? 0 : ((AVLNode<E>)right).height;
height = 1 + Math.max(leftHeight, rightHeight);
}
同样的其实右旋转也很简单:
/**
* 右旋转
*/
private void rotateLeft(Node<E> grand){
Node<E> parent = grand.left;
Node<E> child = parent.right;
grand.left = child;
parent.right = grand;
// 让parent成为子树的根节点
parent.parent = grand.parent;
if(grand.isLeftChild()){
grand.parent.left = parent;
}else if (grand.isRightChild()){
grand.parent.right = parent;
}else{// grand是root节点
root = parent;
}
// 更新child的parent
if(child != null){
child.parent = grand;
}
// 更新grand的parent
grand.parent = parent;
// 更新高度
updateHeight(grand);
updateHeight(parent);
}
4、AVL删除
4.1、删除导致的失衡
- 示例:删除子树中的16
- 可能会导致父节点或祖先节点失衡(只有1个节点会失衡),其他节点,都不可能失衡
如下图所示:我们要删除节点16的话,就会导致父节点失衡
如下图所示:
我们要删除节点16的时候,虽然15节点不会失衡,但是节点11会失衡
4.1.1、LL—右旋转(单旋)
- 如果绿色节点不存在,更高层的祖先节点可能也会失衡,需要再次恢复平衡,然后又可能导致更高层的祖先节点失衡..
- 极端情况下,所有祖先节点都需要进行恢复平衡,功O(logn)次调整
4.1.2、RR—左旋转(单旋)
4.1.3、LR—RR左旋转,LL右旋转(双旋)
4.1.4、RL—LL右旋转,RR左旋转(双旋)
5、总结
- 添加
- 可能会导致所有祖先节点都失衡
- 只要让高度最低的失衡节点恢复平衡;整棵树就恢复平衡(仅需要O(1)次调整)
- 删除
- 可能会导致父节点或祖先节点失衡(只有1个节点会失衡)
- 恢复平衡后,可能会导致更高层的祖先节点失衡(最多需要O(logn)次调整)
- 平均时间复杂度
- 搜索:O(logn)
- 添加:O(logn),仅需O(1)次的旋转操作
- 删除:O(logn),最多需要O(logn)次的旋转操作