二叉树搜索树的时间复杂度 是O(logn) 就是二叉树的高度
二叉搜索树的缺点:
1 当有序添加元素时退化成链表
2 删除节点的时候也会退化成链表
平衡二叉搜索树:当节点数量固定的时候,左右子树的高度越接近,这颗二叉树就越平衡
改进二叉搜索树
首先,节点的添加和删除时无法限制的,
接着,在节点的添加、删除操作之后,想办法让二叉搜索树恢复平衡(减少树的高度)
如果接着继续调整节点的位置,完全可以达到理想平衡,但是付出的代价比较大
如果调整的次数比较多,反而增加了时间复杂度
总结:用尽量少的调整次数达到适度平衡就可以
经典的平衡二叉树
avl树、红黑树
平衡因子:某节点的左右子树的高度差
特点:
每个节点的平衡因子只可能是1 0 -1
每个节点的左右子树的高度差不超过1
搜索、添加、删除的时间复杂度是O(logn)
添加导致的失衡:
可能会导致所有的祖先节点都失衡,但是只要让高度最低的失衡节点恢复平衡,整棵树就平衡了
父节点不会失衡,非祖先节点不会失衡,
ll 右边旋转 单旋 ll的意思是在失衡节点的左边左边
rr 左边旋转 单旋
LR 双旋 先左边,后边右边
RL 双旋 先右边 后左边
总结: 相同字母反,不同字母同
删除导致的失衡:
可能会导致父节点或者祖父节点失衡,但是只有一个能失衡,如果删除导致父节点失衡了,那么这个删除的节点一定是比较短的
让父节点恢复平衡后,可能会导致更高的祖先节点失衡,但是最多需要ologn次调整
package com.xk.algorithm.tree.avl; import com.xk.algorithm.tree.binary.BinarySearchTree; import java.util.Comparator; /** * avl树 * ll 右旋转 * rr 左旋转 * lr 先左旋转后右边旋转 * rl 先右边旋转然后再左边 * 旋转都是成为局部根节点 * * @param <E> */ public class AvlTree<E> extends BinarySearchTree<E> { public AvlTree() { this(null); } /** * 有参构造函数 * * @param comparator 比较器 */ public AvlTree(Comparator<E> comparator) { super(comparator); } @Override protected void afterAdd(Node<E> node) { while ((node = node.parent) != null) { if (isBalanced(node)) { //更新高度 updateHeight(node); } else { //恢复平衡 当前节点一定是不平衡的,一定是平衡最低的 rebalance(node); break; } } } private void rotate( Node<E> r, Node<E> a, Node<E> b, Node<E> c, Node<E> d, Node<E> e, Node<E> f, Node<E> g) { d.parent = r.parent; if (((AvlNode<E>) r).isLeftChild()) { r.parent.left = d; } else if (((AvlNode<E>) r).isRightChild()) { r.parent.right = d; } else { root = d; } //a - b - c b.left = a; if (a != null) { a.parent = b; } if (c != null) { c.parent = b; } b.right = c; updateHeight(b); //e - f -g f.left = e; if (e != null) { e.parent = f; } if (g != null) { g.parent = f; } f.right = g; updateHeight(f); //b-d-f d.left = b; d.right = f; b.parent = d; f.parent = d; updateHeight(d); } private void rebalance(Node<E> grand) { // 确定node parent grand Parent 节点是 比较高的那个 Node<E> parent = ((AvlNode<E>) grand).tallerChild(); Node<E> node = ((AvlNode<E>) parent).tallerChild(); //判断方向 if (((AvlNode<E>) parent).isLeftChild()) { if (((AvlNode<E>) node).isLeftChild()) { //LL // rotateRight(grand); rotate(grand,node.left,node,node.right,parent,parent.right,grand,grand.right); } else { //LR // rotateLeft(parent); // rotateRight(grand); rotate(grand,grand.left,parent,node.left,node,node.right,grand,grand.right); } } else { if (((AvlNode<E>) parent).isLeftChild()) { //RL // rotateRight(parent); // rotateLeft(grand); rotate(grand,grand.left,grand,node.left,node,node.right,parent,parent.right); } else { //RR // rotateLeft(grand); rotate(grand,grand.left,grand,parent.left,parent,node.left,node,node.right); } } } @Override protected void afterRemove(Node<E> node) { while ((node = node.parent) != null) { if (isBalanced(node)) { //更新高度 updateHeight(node); } else { //恢复平衡 当前节点一定是不平衡的,一定是平衡最低的 rebalance(node); } } } private void rotateLeft(Node<E> grand) { Node<E> parent = grand.right; Node<E> child = parent.left; grand.right = child; parent.left = grand; afterRotate(grand, parent, child); } private void rotateRight(Node<E> grand) { Node<E> parent = grand.left; Node<E> child = parent.right; grand.left = child; parent.right = grand; afterRotate(grand, parent, child); } private void afterRotate(Node<E> grand, Node<E> parent, Node<E> child) { //让parent成为根节点 parent.parent = grand.parent; if (((AvlNode<E>) grand).isLeftChild()) { grand.parent.left = parent; } else if (((AvlNode<E>) grand).isRightChild()) { grand.parent.right = parent; } else {//这个是根节点 root = parent; } //更新child的parent if (child != null) { child.parent = grand; } //更新grand的parent grand.parent = parent; //更新高度 先更新矮的 updateHeight(grand); updateHeight(parent); } protected Node<E> createNode(E element, Node<E> parent) { return new AvlNode<>(element, parent); } private boolean isBalanced(Node<E> node) { return Math.abs(((AvlNode<E>) node).balanceFactor()) <= 1; } private void updateHeight(Node<E> node) { ((AvlNode<E>) node).updateHeight(); } private static class AvlNode<E> extends Node<E> { int height = 1; /** * 构造函数 * 没有传递进来左右子树,是因为这两个可能为空 * * @param element 当前节点存储的值 * @param parent 当前节点的父节点 */ public AvlNode(E element, Node<E> parent) { super(element, parent); } public int balanceFactor() { int leftHeight = left == null ? 0 : ((AvlNode<E>) left).height; int rightHight = right == null ? 0 : ((AvlNode<E>) right).height; return leftHeight - rightHight; } public void updateHeight() { int leftHeight = left == null ? 0 : ((AvlNode<E>) left).height; int rightHight = right == null ? 0 : ((AvlNode<E>) right).height; height = 1 + Math.max(leftHeight, rightHight); } /** * 返回左右子树中比较高的 * 如果相同高度,则返回相同方向的 * * @return */ public Node<E> tallerChild() { int leftHeight = left == null ? 0 : ((AvlNode<E>) left).height; int rightHight = right == null ? 0 : ((AvlNode<E>) right).height; if (leftHeight > rightHight) return left; if (leftHeight < rightHight) return right; return isLeftChild() ? left : right; } public boolean isLeftChild() { return parent != null && this == parent.left; } public boolean isRightChild() { return parent != null && this == parent.right; } } }