一、谈二叉搜索树
增加的最坏时间复杂度 | 删除的最坏时间复杂度 | 查询的最坏时间复杂度 | |
链表 | O(N) + O(1) | O(N) + O(1) | O(N) |
---|---|---|---|
二叉搜索树 | O(N) + O(1) | O(N) + O(1) | O(N) |
对于二叉搜索树,如果添加数据的时候数据随机分布的话,插入结点的时间复杂度会是O(h)、O(logN)。但是考虑下面两种极端情况,当**数据从小到大或者从大到小插入**的时候,裂开,复杂度直接变为O(N),而且**二叉搜索树变得和普通链表**一样了。
不但插入结点会凉凉,删除结点可能也会变成链表,考虑下面情况:
其实出现上述情况的根源还是二叉搜索树失衡了。
二、AVL树
1、AVL树(自平衡)特点
每个结点的平衡因子的绝对值小于等于1,一旦超过就是失衡,balanceFactor计算方法:平衡因子 = 左子树高度 - 右子树高度
。
AVL树增加删除查询结点的时间复杂度都是O(h)、O(logN)。
2、设计结构图:
3、注意点
写代码要搞清楚以下两个点:
① 什么时候会出现失衡?
二叉搜索树插入结点和删除结点的时候会出现失衡情况。其实插入结点和删除结点也是不一样的,插入结点造成的失衡,只要往上找到第一个失衡的祖父结点,之后旋转同时将该结点及子结点的高度更新后,祖父结点之上失衡的结点也会变得平衡。然后删除结点恰恰相反,可能牵一发而动全身,不过最坏情况也不过是执行O(logN)次旋转操作。
② 怎么解决失衡?四种旋转情况对号入座
4、四种旋转情况(g、p、n三个结点)分析
第一种情况:LL造成的失衡,g结点右旋转。
第二种情况:RR造成的失衡,g结点左旋转。
第三种情况:LR造成的失衡,先将p结点左旋转,再将g结点右旋转。
第四种情况:RL造成的失衡,先将p结点右旋转,再将g结点左旋转。
旋转情况比较简单,主要还是确定三个点,这三个点都是结点左右子树中比较长的结点。其中三个点用来判断是哪一种旋转情况,而 g 和 p 结点是专门用来旋转的。
模板设计模式搭好AVL树插入结点和删除结点的算法框架,在之前BST插入代码里面写好接口,AVL树实现相应解决失衡的方法。
5、代码实现
public class BinarySearchTree<E> extends BinaryTree<E> {
private Comparator<E> comparator;
public BinarySearchTree(Comparator<E> comparator) {
this.comparator = comparator;
}
public BinarySearchTree() {
this(null); //调用有参构造
}
private int compare(E e1, E e2) {
if (comparator != null)
return comparator.compare(e1, e2);
else
return ((Comparable) e1).compareTo(e2);
}
public boolean contains(E element) {
return getNode(element) != null;
}
public Node<E> getNode(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;
}
protected Node<E> createNode(Node<E> parent, E element) {
return new Node(parent, element);
}
/**
* BST插入一个结点
*
* @param element
*/
public void add(E element) {
Node<E> node = root;
if (root == null) { //插入第一个结点
root = createNode(null, element);
size++;
afterAdd(root); //判断祖父结点们是否失衡在子类里进行处理
return;
}
int cmp = 0;
Node<E> t = null;
while (node != null) {
t = node;
cmp = compare(element, node.element);
if (cmp > 0) { //待插入的元素比根结点元素大
node = node.right;
} else if (cmp < 0) { //待插入的元素比根结点元素小
node = node.left;
} else {
return;
}
}
if (cmp > 0) {
t.right = createNode(t, element);
afterAdd(t.right); //判断祖父结点们是否失衡在子类里进行处理
} else {
t.left = createNode(t, element);
afterAdd(t.left); //判断祖父结点们是否失衡在子类里进行处理
}
size++;
}
/**
* 模板设计模式 交给子类来实现
*
* @param node
*/
protected void afterAdd(Node<E> node) {}
/**
* BST删除节点要分情况, 度为0、1、2
*
* @param element
*/
public void remove(E element) {
Node<E> node = getNode(element);
if (node == null)
return;
if (getDegree(node) == 0) { //度为0, 直接删除即可
if (node.parent == null) //只有一个根结点
root = null;
if (node == node.parent.left)
node.parent.left = null;
else
node.parent.right = null;
afterRemove(node); //判断祖父结点们是否失衡在子类里进行处理
} else if (getDegree(node) == 1) { //度为1, 找自己的左儿子或右儿子替代
if (node.left != null) { //找左儿子代替
if (node.parent == null) //只有一个根结点
root = node.left;
if (node.parent.left == node) {
node.parent.left = node.left;
node.left.parent = node.parent; //改变父结点
} else {
node.parent.right = node.left;
node.left.parent = node.parent; //改变父结点
}
afterRemove(node); //判断祖父结点们是否失衡在子类里进行处理
} else { //找右儿子代替
if (node.parent == null) //只有一个根结点
root = node.right;
if (node.parent.left == node) {
node.parent.left = node.right;
node.right.parent = node.parent; //改变父结点
} else {
node.parent.right = node.right;
node.right.parent = node.parent; //改变父结点
}
afterRemove(node); //判断祖父结点们是否失衡在子类里进行处理
}
} else { //度为2, 找前驱或者后继, 拷贝数据然后删除找的结点
Node<E> t = getSuccessor(node);
node.element = t.element;
int s = getDegree(t); //前驱结点和后继结点只可能是度为1或者度为0
if (s == 1) { //度为1
if (t.left != null) {
if (t.parent.left == t) {
t.parent.left = t.left;
t.left.parent = t.parent;
} else {
t.parent.right = t.left;
t.left.parent = t.parent;
}
afterRemove(t); //判断祖父结点们是否失衡在子类里进行处理
} else {
if (t.parent.left == t) {
t.parent.left = t.right;
t.right.parent = t.parent;
} else {
t.parent.right = t.right;
t.right.parent = t.parent;
}
afterRemove(t); //判断祖父结点们是否失衡在子类里进行处理
}
} else { //度为0
if (t.parent.left == t)
t.parent.left = null;
else
t.parent.right = null;
afterRemove(t); //判断祖父结点们是否失衡在子类里进行处理
}
}
}
/**
* 模板设计模式 交给子类来实现
*
* @param node
*/
protected void afterRemove(Node<E> node) {}
}
public class AVLTree<E> extends BinarySearchTree<E> {
public AVLTree(Comparator<E> comparator) {
super(comparator);
}
public AVLTree() {
super();
}
private class AVLNode<E> extends Node<E> {
private int height = 1;
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public AVLNode(Node parent, E element) {
super(parent, element);
}
/**
* 计算平衡因子
*
* @return
*/
public int balanceFactor() {
int leftHeight = this.left == null ? 0 : ((AVLNode<E>) this.left).height;
int rightHeight = this.right == null ? 0 : ((AVLNode<E>) this.right).height;
return leftHeight - rightHeight;
}
/**
* 更新高度
*/
public void updateHeight() {
int leftHeight = this.left == null ? 0 : ((AVLNode<E>) this.left).height;
int rightHeight = this.right == null ? 0 : ((AVLNode<E>) this.right).height;
height = 1 + Math.max(leftHeight, rightHeight);
}
/**
* 找到自己的左右子树中长的那个
*
* @return
*/
public Node getTallerChild() {
int leftHeight = this.left == null ? 0 : ((AVLNode<E>) this.left).height;
int rightHeight = this.right == null ? 0 : ((AVLNode<E>) this.right).height;
if (leftHeight > rightHeight)
return left;
else
return right;
// TODO 相等情况
}
}
private boolean isBalance(Node<E> node) {
return Math.abs(((AVLNode<E>) node).balanceFactor()) <= 1;
}
private void updateHeight(Node<E> node) {
((AVLNode<E>) node).updateHeight();
}
@Override
protected Node<E> createNode(Node<E> parent, E element) {
return new AVLNode(parent, element);
}
/**
* 左旋转
*
* @param g
*/
private void rotateLeft(Node<E> g) { //只需要动g 和 p
Node<E> p = g.right;
g.right = p.left;
p.left = g;
//p变为根结点
p.parent = g.parent;
if (g.parent == null) { //旋转的是根结点
root = p;
} else if (g.parent.left == g)
g.parent.left = p;
else if (g.parent.right == g)
g.parent.right = p;
//改变其他结点的parent
if (g.right != null)
g.right.parent = g;
g.parent = p;
//更新高度
updateHeight(g);
updateHeight(p);
}
/**
* 右旋转
*
* @param g
*/
private void rotateRight(Node<E> g) { //只需要动g 和 p
Node<E> p = g.left;
g.left = p.right;
p.right = g;
//p变为根结点
p.parent = g.parent;
if (g.parent == null) { //旋转的是根结点
root = p;
} else if (g.parent.left == g)
g.parent.left = p;
else if (g.parent.right == g)
g.parent.right = p;
//改变其他结点的parent
if (g.left != null)
g.left.parent = g;
g.parent = p;
//更新高度
updateHeight(g);
updateHeight(p);
}
@Override
protected void afterAdd(Node<E> n) {
Node<E> grandparent = n;
while ((grandparent = grandparent.parent) != null) {
if (isBalance(grandparent)) { //结点平衡直接更新高度
updateHeight(grandparent);
} else { //结点不平衡需要旋转操作
//先找到g p n 三个结点(g是第一个不平衡结点中比较长的孩子结点)
Node<E> parent = ((AVLNode<E>) grandparent).getTallerChild();
Node<E> node = ((AVLNode<E>) parent).getTallerChild();
if (grandparent.left == parent) {
if (parent.left == node) { //LL
rotateRight(grandparent);
} else if (parent.right == node) { //LR
rotateLeft(parent);
rotateRight(grandparent);
}
} else if (grandparent.right == parent) {
if (parent.left == node) { //RL
rotateRight(parent);
rotateLeft(grandparent);
} else if (parent.right == node) { //RR
rotateLeft(grandparent);
}
}
break; //添加结点引起的失衡只需旋转一次
}
}
}
@Override
protected void afterRemove(Node<E> n) {
Node<E> grandparent = n;
while ((grandparent = grandparent.parent) != null) {
if (isBalance(grandparent)) { //结点平衡直接更新高度
updateHeight(grandparent);
} else { //结点不平衡需要旋转操作
//先找到g p n 三个结点(g是第一个不平衡结点中比较长的孩子结点)
Node<E> parent = ((AVLNode<E>) grandparent).getTallerChild();
Node<E> node = ((AVLNode<E>) parent).getTallerChild();
if (grandparent.left == parent) {
if (parent.left == node) { //LL
rotateRight(grandparent);
} else if (parent.right == node) { //LR
rotateLeft(parent);
rotateRight(grandparent);
}
} else if (grandparent.right == parent) {
if (parent.left == node) { //RL
rotateRight(parent);
rotateLeft(grandparent);
} else if (parent.right == node) { //RR
rotateLeft(grandparent);
}
}
//删除结点引起的失衡可能不止一次不要直接break
}
}
}
}