平衡二叉搜索树
如果二叉排序树是平衡的,则n个节点的二叉排序树的高度为,其查找效率为
,近似于折半查找。
如果二叉排序树完全不平衡,则其深度可达到n,查找效率为O(n),退化为顺序查找。一般的,二叉排序树的查找性能在到O(n)之间。
因此,为了获得较好的查找性能,就要构造一棵平衡的二叉排序树。
平衡
- 当节点数量固定时,左右子树的高度越接近,这颗二叉树就越平衡(高度越低)
- 最理想的平衡,就是像完全二叉树、满二叉树那样,高度是最小的
如何改进二叉树搜索树
- 首先,节点的添加、删除是无法限制的,可以认为是随机的
- 所以,改进方案是:在节点的添加、删除之后,想办法让二叉搜索树恢复平衡(减小树的高度)
- 如果接着继续调整节点的位置,完全可以达到理想平衡,但是付出的代价可能会比较大
比如调整的次数会比较多,反而增加了时间复杂度
- 总结来说,比较合理的改进方案是:用尽量少的调整次数达到适度平衡即可
- 一棵达到适度平衡的二叉搜索树,可以称之为:平衡二叉搜索树
平衡二叉树搜索树
- AVL树
- 红黑树
AVL树
- 平衡因子(Balance Factor):某节点的左右子树的高度差
- AVL树的特点:每个节点的平衡因子只可能是1、0、-1
- 每个节点的左右子树的高度差不超过1
- 搜索、添加、删除的时间复杂度O(logn)
平衡对比
- 输入数据:35、37、34、56、25、62、57、9、74、32、94、80、75、100、16、82
添加导致的失衡
- 例子:往下面这棵子树中添加13
- 最坏情况:可能会导致所有祖先节点都失衡
- 父节点、非祖先节点,都不可能失衡
LL-右旋转(单旋)
-
g.left = p.right
-
p.right = g
-
让p成为这棵树的根节点
-
仍然是一棵二叉搜索树:T0<n<T1<P<T2<g<T3
-
整棵树都达到平衡
-
还需要注意维护的内容
1、T2、P、G 的parent属性
2、先后更新g、p的高度
RR-左旋转(单旋)
1、T2、P、G 的parent属性
2、先后更新g、p的高度
- g.right = p.left
- p.left = g
- 让p成为这棵子树的根节点
-
仍然是一棵二叉搜索树:T0<G<T1<P<T2<N<T3
-
整棵树都达到平衡
-
还需要注意维护的内容
LR-RR左旋转,LL右旋转
RL- LL右旋转,RR左旋转
删除导致的失衡
- 删除下面的这棵子树中的16
- 只可能导致父节点失衡或祖先节点失衡(只有1个节点失衡)
- 除父节点以外的节点,都不可能失衡
代码
package com.jvm.letcode;
import java.util.LinkedList;
import java.util.Queue;
public class BinaryTree<E> {
protected int size;
protected Node<E> root;
// 清空所有元素
public void clear() {
root = null;
size = 0;
}
// 元素的数量
public int size() {
return size;
}
// 是否为空
public boolean isEmpty() {
return size == 0;
}
/**
* 前序遍历
*/
public void preorder(Visitor<E> visitor) {
preorderTraversal(root, visitor);
}
public void preorderTraversal(Node<E> node, Visitor<E> visitor) {
if (node == null) return;
preorderTraversal(node.left, visitor);
preorderTraversal(node.right, visitor);
}
/**
* 中旬遍历
*/
public void inorder(Visitor<E> visitor) {
inorder(root, visitor);
}
public void inorder(Node<E> node, Visitor<E> visitor) {
if (node == null) return;
inorder(node.left, visitor);
visitor.visit(node.element);
inorder(node.right, visitor);
}
/**
* 后续遍历
*/
public void postorder(Visitor<E> visitor) {
postorder(root, visitor);
}
public void postorder(Node<E> node, Visitor<E> visitor) {
if (node == null) return;
postorder(node.left, visitor);
postorder(node.right, visitor);
System.out.println("BinarySearchTree.inorderTraversal:" + node.element);
}
/**
* 层序遍历
*/
public void levelOrder(Visitor<E> visitor) {
if (root == null || visitor == null) return;
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
Node<E> node = queue.poll();
visitor.visit(node.element);
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
}
/**
* 获取前驱节点
*
* @param node
* @return
*/
protected Node<E> predecessor(Node<E> node) {
if (node == null) return null;
Node<E> p = node.left;
// 前驱节点在左子树当中 left.right.right.right
if (p != null) {
while (p.right != null) {
p = p.right;
}
return p;
}
// 从父节点、祖父节点中国呢寻找前驱节点
Node<E> parent = node.parent;
while (parent != null && node == node.parent.left) {
node = node.parent;
}
return node.parent;
}
/**
* 获取后继节点
*
* @param node
* @return
*/
protected Node<E> successor(Node<E> node) {
if (node == null) return null;
Node<E> p = node.right;
if (p != null) {
while (p.left != null) {
p = p.left;
}
return p;
}
Node<E> parent = node.parent;
while (parent != null && node == node.parent.right) {
node = node.parent;
}
return node.parent;
}
public Integer hight() {
return hight(root);
}
public int hight(Node<E> node) {
if (node == null) return 0;
return 1 + Math.max(hight(node.left), hight(node.right));
}
public Integer hight2() {
if (root == null) return 0;
Queue<Node<E>> queue = new LinkedList<>();
int queueSize = 1;
int hight = 0;
queue.offer(root);
while (!queue.isEmpty()) {
Node<E> node = queue.poll();
queueSize--;
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
if (queueSize == 0) {
queueSize = queue.size();
hight++;
}
}
return hight;
}
public boolean isComplete() {
if (root == null) return false;
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
boolean leaf = false;
while (!queue.isEmpty()) {
Node<E> node = queue.poll();
if (leaf && !node.isLeaf()) return false;
if (node.hasTwoChildren()) {
queue.offer(node.left);
queue.offer(node.right);
} else if (node.left == null && node.right != null) {
return false;
} else {
// 判断是否都是叶子节点
leaf = true;
if (node.left != null) {
queue.offer(node);
}
}
}
return true;
}
public boolean isCompleteOther() {
if (root == null) return false;
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
boolean leaf = false;
while (!queue.isEmpty()) {
Node<E> node = queue.poll();
if (leaf && !node.isLeaf()) return false;
if (node.left != null) {
queue.offer(node.left);
} else if (node.right != null) {
//node.left == null && node.right!=null,
return false;
}
if (node.right != null) {
queue.offer(node.right);
} else {
//node.left !=null && node.right==null 或者 node.left ==null && node.right == null
leaf = true;
}
}
return true;
}
public Object root() {
return root;
}
public Object left(Object node) {
return ((Node<E>) node).left;
}
public Object right(Object node) {
return ((Node<E>) node).right;
}
public Object string(Object node) {
return ((Node<E>) node).element;
}
protected Node<E> createNode(E element, Node<E> parent) {
return new Node<>(element, parent);
}
/**
* 遍历接口
*
* @param <E>
*/
public static interface Visitor<E> {
void visit(E element);
}
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;
}
public boolean isLeaf() {
return left == null && right == null;
}
public boolean hasTwoChildren() {
return left != null && right != null;
}
public boolean isLeftChild() {
return parent != null && this == parent.left;
}
public boolean isRightChild() {
return parent != null && this == parent.right;
}
}
}
package com.jvm.letcode;
/**
* 二叉搜索树
*
* @param <E>
*/
public class BinarySearchTree<E> extends BinaryTree {
private Comparator<E> comparator;
public BinarySearchTree(Comparator<E> comparator) {
this.comparator = comparator;
}
// 添加元素
public void add(E element) {
elementNotNullCheck(element);
if (root == null) {
// 添加第一个节点
root = createNode(element,null);
size++;
afterAdd(root);
return;
}
// 添加不是第一个节点
// 找到父节点
Node<E> parent = null;
Node<E> node = root;
int cmp = 0;
while (node != null) {
cmp = compare(element, node.element);
parent = node;
if (cmp > 0) {
node = node.right;
} else if (cmp < 0) { // 新加的元素比父节点小
node = node.left;
} else { // 相等 将对象覆盖
node.element = element;
return;
}
}
// 看看插入到副节点的哪个位置
Node<E> newNode = createNode(element, parent);
if (cmp > 0) {
parent.right = newNode;
} else {
parent.left = newNode;
}
size++;
afterAdd(newNode);
}
protected void afterAdd(Node<E> node){
}
private int compare(E element1, E element2) {
return comparator.comparator(element1, element2);
}
// 删除元素
public void remove(E elemet) {
remove(node(elemet));
}
// 删除元素
public void remove(Node<E> node) {
if (node == null) return;
size--;
// 度为2的节点
if (node.hasTwoChildren()) {
// 找到后继节点
Node<E> s = successor(node);
// 用后继节点的值 覆盖度为2的节点的值
node.element = s.element;
// 删除后继节点
node = s;
}
// 删除node节点(node的度必然是1 或者 0)
Node<E> repalcement = node.left != null ? node.left : node.right;
if (repalcement != null) { // node的度是1
// 更改
repalcement.parent = node.parent;
if (node.parent == null) {// node的度是1 并且是根节点
root = repalcement;
} else if (node == node.parent.left) {
node.parent.left = repalcement;
} else if (node == node.parent.right) {
node.parent.right = repalcement;
}
} else if (node.parent == null) { // node的度是0 叶子节点 并且是根节点
root = null;
} else { // node的度是0 叶子节点 但不是根结点
if (node == node.parent.right) {
node.parent.right = null;
} else {
node.parent.left = null;
}
}
}
private Node<E> node(E element) {
Node<E> node = root;
while (node != null) {
int cmp = compare(element, node.element);
if (cmp > 0) {
node = node.right;
} else if (cmp < 0) { // 新加的元素比父节点小
node = node.left;
} else { // 相等 将对象覆盖
return node;
}
}
return null;
}
// 是否包含某元素
public boolean contains(E element) {
return node(element) != null;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
toString(root, sb, "");
return sb.toString();
}
public void toString(Node<E> node, StringBuilder sb, String prefix) {
if (node == null) return;
toString(node.left, sb, prefix + "L---");
sb.append(prefix).append(node.element).append("\n");
toString(node.right, sb, prefix + "R---");
}
private void elementNotNullCheck(E element) {
if (element == null) {
throw new IllegalArgumentException("element must not be null");
}
}
public static void main(String[] args) {
Integer[] a = new Integer[]{7, 4, 9, 2, 1, 3, 5, 9, 8, 11, 10, 12};
BinarySearchTree<Integer> bst = new BinarySearchTree<Integer>(new Comparator<Integer>() {
@Override
public int comparator(Integer e1, Integer e2) {
return e1 - e2;
}
});
for (Integer i : a) {
bst.add(i);
}
System.out.println("BinarySearchTree.main:" + bst.hight2());
System.out.println("BinarySearchTree.main:" + bst.hight());
bst.levelOrder(new Visitor<Integer>() {
@Override
public void visit(Integer element) {
System.out.println("_" + element + "_");
}
});
}
}
package com.jvm.letcode;
public class AVLTree<E> extends BinarySearchTree<E> {
public AVLTree() {
this(null);
}
public AVLTree(Comparator<E> comparator) {
super(comparator);
}
@Override
protected void afterAdd(Node<E> node) {
while ((node = node.parent) != null) {
if (isBalanced(node)) {
// 更新高度
((AVLNode<E>) node).updateHight();
} else {
// 恢复平衡
AVLNode<E> grand = ((AVLNode<E>) node);
Node<E> parent = grand.tallerChild();
Node<E> no = ((AVLNode<E>) parent).tallerChild();
if (parent.isLeftChild()) { // L
if (no.isLeftChild()) { // LL
rotateRight(grand);
} else { // LR
rotateLeft(parent);
rotateLeft(grand);
}
} else { // R
if (no.isLeftChild()) { // RL
rotateRight(parent);
rotateRight(grand);
} else {// RR
rotateLeft(grand);
}
}
break;
}
}
}
private void rotateLeft(Node<E> grand) {
Node<E> parent = grand.right;
Node<E> child = grand.left;
grand.right = child;
parent.left = grand;
parent.parent = grand.parent;
if (grand.isLeftChild()) {
grand.parent.left = parent;
} else if (grand.isRightChild()) {
grand.parent.right = parent;
} else {
root = parent;
}
if (child != null) {
child.parent = grand;
}
grand.parent = parent;
// 更新高度
((AVLNode<E>) grand).updateHight();
((AVLNode<E>) parent).updateHight();
}
private void rotateRight(Node<E> grand) {
Node<E> parent = grand.left;
Node<E> child = grand.right;
grand.left = child;
parent.right = grand;
parent.parent = grand.parent;
if (grand.isLeftChild()) {
grand.parent.left = parent;
} else if (grand.isRightChild()) {
grand.parent.right = parent;
} else {
root = parent;
}
if (child != null) {
child.parent = grand;
}
grand.parent = parent;
// 更新高度
((AVLNode<E>) grand).updateHight();
((AVLNode<E>) parent).updateHight();
}
private boolean isBalanced(Node<E> node) {
return Math.abs(((AVLNode<E>) node).balanceFactor()) <= 1;
}
private class AVLNode<E> extends Node<E> {
int height = 1;
public AVLNode(E element, Node<E> parent) {
super(element, parent);
}
public int balanceFactor() {
int leftHeight = left == null ? 0 : ((AVLNode<E>) left).height;
int rightHeight = right == null ? 0 : ((AVLNode<E>) right).height;
return leftHeight - rightHeight;
}
public void updateHight() {
int leftHeight = left == null ? 0 : ((AVLNode<E>) left).height;
int rightHeight = right == 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 = right == null ? 0 : ((AVLNode<E>) right).height;
if (leftHeight > rightHeight) return left;
if (leftHeight < rightHeight) return right;
return isLeftChild() ? left : right;
}
}
@Override
protected Node createNode(Object element, Node parent) {
return new AVLNode(element, parent);
}
}