以下是学习恋上数据结构与算法的记录,本篇主要内容是二叉搜索树
◼平衡二叉搜索树(Balanced Binary Search Tree)
●二叉搜索树的复杂度分析
添加、删除节点时,都可能会导致二叉搜索树退化成链表
●平衡(Balance)
●如何改进二叉搜索树?
◼首先,节点的添加、删除顺序是无法限制的,可以认为是随机的
◼所以,改进方案是:在节点的添加、删除操作之后,想办法让二叉搜索树恢复平衡(减小树的高度)
◼如果接着继续调整节点的位置,完全可以达到理想平衡,但是付出的代价可能会比较大,比如调整的次数会比较多,反而增加了时间复杂度
◼总结来说,比较合理的改进方案是:用尽量少的调整次数达到适度平衡即可
◼一棵达到适度平衡的二叉搜索树,可以称之为:平衡二叉搜索树
◼经典常见的平衡二叉搜索树有
AVL树
✓WindowsNT 内核中广泛使用
红黑树
C++STL(比如map、set )Java 的TreeMap、TreeSet、HashMap、HashSet 、Linux 的进程调度、 Ngix 的timer 管理
●一般也称它们为:自平衡的二叉搜索(SelfbalancingBinarySearchTree)
◼AVL树
◼平衡因子(Balance Factor):某结点的左右子树的高度差
◼AVL树的特点:每个节点的平衡因子只可能是1、0、-1(绝对值≤ 1,如果超过1,称之为“失衡”)
●每个节点的左右子树高度差不超过1
●搜索、添加、删除的时间复杂度是O(logn)
接口简单设计
◼添加导致的失衡
●添加:只要让高度最低的失衡节点恢复平衡,整棵树就恢复平衡【仅需O(1) 次调整】
private boolean isBalanced(Node<E> node) {
return Math.abs(((AVLNode<E>)node).balanceFactor()) <= 1;
}
protected void afterAdd(Node<E> node) {
while(node.parent!=null) {
if(isBalanced(node)) {
//更新高度
updateHeight(node);
}else {
//恢复平衡
rebalance(node);
// 整棵树恢复平衡
break;
}
}
}
◼删除导致的失衡
●删除:恢复平衡后,可能会导致更高层的祖先节点失衡,最多需要O(logn) 次调整
protected void afterRemove(Node<E> node) {
while(node.parent!=null) {
if(isBalanced(node)) {
//更新高度
updateHeight(node);
}else {
//恢复平衡
rebalance(node);
}
}
}
●LL–右旋转(单旋)
LL情况:当前n节点是祖父节点的左子树的左子树时,就是左左。
则右旋转使其平衡,
具体为:祖父节点g指向父节点p的右子树,并父节点p成为这颗子树的根节点,祖父节点g成为父节点p的子树,更改的只有红线部分。
private void rotateRight(Node<E> grand) {
//交换子树
Node<E> parent = grand.left;
Node<E> child = parent.right;
grand.left = child;
parent.right = grand;
//维护parent和hegiht
afterRotate(grand, parent, child);
}
●RR –左旋转(单旋)
RR情况:当前n节点是祖父节点的右子树的右子树时,就是右右。
则左旋转使其平衡。
具体为:祖父节点g指向父节点p的左子树,并父节点p成为这颗子树的根节点,祖父节点g成为父节点p的子树,更改的只有红线部分。
private void rotateLeft(Node<E> grand) {
//交换子树
Node<E> parent = grand.right;
Node<E> child = parent.left;
grand.right=child;
parent.left=grand;
//维护parent和hegiht
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节点
root = parent;
}
// 更新child的parent
if (child != null) {
child.parent = grand;
}
// 更新grand的parent
grand.parent = parent;
// 更新高度
updateHeight(grand);
updateHeight(parent);
}
●LR –RR左旋转,LL右旋转(双旋)
父节点P先左旋转,然后祖父节点G右旋转
●RL –LL右旋转,RR左旋转(双旋)
父节点p先右旋转,然后祖父节点g左旋转
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
rotateRight(grand);
}else {//LR
rotateRight(parent);
rotateLeft(grand);
}
}else {//R
if(node.isLeftChild()) {//RL
rotateRight(parent);
rotateLeft(grand);
}else {//RR
rotateLeft(grand);
}
}
}
◼独立出AVLNode
private static class AVLNode<E> extends Node<E> {
int height = 1;
public AVLNode(E element, Node<E> parent) {
super(element, parent);
// TODO Auto-generated constructor stub
}
//平衡因子
public int balanceFactor() {
int leftheight = left ==null ? 0:((AVLNode<E>)left).height;
int rightheight = left ==null ? 0:((AVLNode<E>)right).height;
return leftheight-rightheight;
}
//更新高度
public void updateHeight() {
int leftheight = left ==null ? 0:((AVLNode<E>)left).height;
int rightheight = left ==null ? 0:((AVLNode<E>)right).height;
height=1+Math.max(leftheight, rightheight);
}
//判断左右子树
public Node<E> tallerChild() {
int leftheight = left ==null ? 0:((AVLNode<E>)left).height;
int rightheight = left ==null ? 0:((AVLNode<E>)right).height;
if (leftheight > rightheight) return left;
if (leftheight < rightheight) return right;
return isLeftChild() ? left : right;
}
@Override
public String toString() {
String parentString = "null";
if (parent != null) {
parentString = parent.element.toString();
}
return element + "_p(" + parentString + ")_h(" + height + ")";
}
}
◼平均时间复杂度:搜索:O(logn)、添加:O(logn),仅需O(1) 次的旋转操作,删除:O(logn),最多需要O(logn) 次的旋转操作。