- 写在前面:记录学习《恋上数据结构与算法》的过程。
- 课程链接地址:https://ke.qq.com/course/385223
目录
平衡二叉搜索树(Balance Binary Search Tree)
平衡
理想平衡
如何改进二叉搜索树
平衡二叉搜索树(Balance Binary Search Tree)
AVL树
平衡对比
简单的继承结构
添加导致的失衡
LL 右旋转(单旋)
- 添加节点,g失去平衡
- 拿到左子树的右子树,整体变左子树的右子树
RR 左旋转(单旋)
- 拿到右子树的左子树,整体变右子树的左子树
LR - RR左旋转,LL右旋转(双旋)
- 先对p进行左旋转,再对g进行右旋转
RL - LL右旋转,RR左旋转(双旋)
afterAdd
- 添加元素之后,进行失衡调整
- BST.java中
- AVLTree.java中
- 新增加的节点可能不导致失衡
- 新增加节点导致失衡,向上找到第一个失衡的祖先
计算平衡因子
- 在BinaryTree.java中,添加
- BST.java中
- 在AVLTree.java中
- 计算平衡因子
更新高度
- 新增的节点必然是叶子节点
- 叶子节点创建出来高度就是1,向上看其父节点,祖先节点
- 每一个节点更新自己的高度
- 强转节点类型(封装一层)
- 更新高度
恢复平衡
- 在BinaryTree.java中,增加判断是否为左子树或者右子树
- 在AVLTree.java中,求子树中较长的树
旋转方向的判断
左旋转的实现
右旋转的实现
代码整合
测试
- AVLTree.java重写toString
示例
统一旋转操作
private void rebalance(Node<E> grand) {
Node<E> parent = ((AVLNode<E>)grand).tallerChild();
Node<E> node = ((AVLNode<E>)parent).tallerChild();
if (parent.isLeftChild()) { // L
if (node.isLeftChild()) { // LL
rotate(grand, node, node.right, parent, parent.right, grand);
} else { // LR
rotate(grand, parent, node.left, node, node.right, grand);
}
} else { // R
if (node.isLeftChild()) { // RL
rotate(grand, grand, node.left, node, node.right, parent);
} else { // RR
rotate(grand, grand, parent.left, parent, node.left, node);
}
}
}
private void rotate(
Node<E> r, // 子树的根节点
Node<E> b, Node<E> c,
Node<E> d,
Node<E> e, Node<E> f) {
// 让d成为这棵子树的根节点
d.parent = r.parent;
if (r.isLeftChild()) {
r.parent.left = d;
} else if (r.isRightChild()) {
r.parent.right = d;
} else {
root = d;
}
//b-c
b.right = c;
if (c != null) {
c.parent = b;
}
updateHeight(b);
// e-f
f.left = e;
if (e != null) {
e.parent = f;
}
updateHeight(f);
// b-d-f
d.left = b;
d.right = f;
b.parent = d;
f.parent = d;
updateHeight(d);
}
- 测试:
删除导致失衡
LL 右旋转(单旋)
RR 左旋转(单旋)
LR - RR左旋转,LL右旋转(双旋)
RL - LL右旋转,RR左旋转(双旋)
afterRemove代码实现
- BST.java中
- AVLTree.java