自平衡二分搜索树
特点
除了同上篇的二分搜索树, 还有一个重要的特点:任意节点的平衡因子的绝对值不能大于1
- 高度:我们定义叶子节点的高度为1, 叶子节点的子节点(null)高度为0; 父节点的高度为左右子节点中的最大高度加1: max(height(left), height(right)) + 1。
- 平衡因子:节点的左右子节点高度差
- 储存的数据, 依然是K具有可比较性。
实现代码
public class AVLTree<K extends Comparable<E>, V> {
private class Node {
public K key;
public V value;
public Node left;
public Node right;
// 描述节点高度
public int height;
public Node(K key, V value, Node left, Node right, int height) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
this.height = height;
}
public Node(K key, V value) {
// 默认构造左右子节点都为空, 高度为1
this(key, value, null, null, 1)
}
}
private Node root;
private int size;
public AVLTree() {
root = null;
size = 0;
}
public int getSize() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
// 获取高度
public int getHeight(Node node) {
return node == null ? 0 : node.height;
}
// 获取平衡因子
public int getBanlanceFactor(Node node)){
if (node == null) return 0;
return getHeight(node.left) - getHeight(node.right)
}
// 节点左旋
// 节点逆时针方向旋转,同时保持树的特性
// 旋转节点的 右子节点的 左子节点 赋值为 旋转节点的右子节点
// 旋转节点的 右子节点的 左子节点 赋值为旋转节点
// 图例(旋转节点 y):
// y x
// / \ / \
// T1 x 向左旋转 (y) y z
// / \ - - - - - - - -> / \ / \
// T2 z T1 T2 T3 T4
// / \
// T3 T4
private Node leftRotate(Node y) {
Node x = y.right;
// 两步
y.right= x.left;
x.left = y;
// 维护x,y的高度, 先维护子节点的高度
y.height = Math.max(getHeight(y.left), getHeight(y.right)) + 1;
x.height = Math.max(getHeight(x.left), getHeight(x.right)) + 1;
return x;
}
// 节点右旋
private Node rightRotate(Node y) {
Node x = y.left;
// 两步
y.left= x.right;
x.right = y;
// 维护x,y的高度, 先维护子节点的高度
y.height = Math.max(getHeight(y.left), getHeight(y.right)) + 1;
x.height = Math.max(getHeight(x.left), getHeight(x.right)) + 1;
return x;
}
// 添加元素
public void add(K key, V value) {
root = add(root, key, value);
}
private Node add(Node node, K key, V value) {
if (node == null) {
size++;
return new Node(key, value);
}
if (key.compareTo(node.key) > 0) {
node.right = add(node.right, key, value)
}else if (key.compareTo(node.key) < 0) {
node.left = add(node.left, key, value)
}else {
node.value = value;
}
// 维护高度
node.height = Math.max(getHeight(x.left), getHeight(x.right)) + 1
// 检测 node 的平衡性
if (getBanlanceFactor(node) > 1) {
// 树整体向左倾斜, 需要右旋
// 但是考虑一种情况:
// node的左节点的右子节点高度大于node的左节点的左子节点高度,也就是平衡因子小于0,
// 但是不会小于 -1,因为node的右子节点肯定是平衡的
// 此时需要先把node左节点左旋
if (getBanlanceFactor(node.left) < 0) {
node.left = leftRotate(node.left);
}
node = rightRotate(node);
}else if (getBanlanceFactor(node) < -1) {
// 树整体向右倾斜, 需要左旋, 同理, 也要考虑上面那种情况
if (getBanlanceFactor(node.right) > 0) {
node.rightt = rightRotate(node.right);
}
node = leftRotate(node);
}
return node;
}
// 删除节点
public V remove(K key) {
Node retNode = getNode(key);
if (retNode != null) {
root = remove(root, K key);
return retNode.value;
}
return null;
}
private Node remove(Node node, K key) {
if (node == null) {
return null;
}
Node ret = null;
if (key.compareTo(node.key) > 0) {
node.right = remove(node.right, key)
}else if (key.compareTo(node.key) < 0) {
node.left = remove(node.left, key)
}else {
// 实现代码
if (node.left == null) {
ret = node.right;
// 释放空间
node.right = null;
size--;
}else if (node.right == null) {
ret = node.left;
// 释放空间
node.left = null;
size--;
}else {
Node succeedNode = minimum(node.right);
succeedNode.left = node.left;
succeedNode.right = remove(node.right, succeedNode.key)
node.left = node.right = null;
ret = succeedNode;
}
Node node = ret;
// 维护高度
node.height = Math.max(getHeight(x.left), getHeight(x.right)) + 1
// 检测 node 的平衡性
if (getBanlanceFactor(node) > 1) {
// 树整体向左倾斜, 需要右旋
// 但是考虑一种情况:
// node的左节点的右子节点高度大于node的左节点的左子节点高度,也就是平衡因子小于0,
// 但是不会小于 -1,因为node的右子节点肯定是平衡的
// 此时需要先把node左节点左旋
if (getBanlanceFactor(node.left) < 0) {
node.left = leftRotate(node.left);
}
node = rightRotate(node);
}else if (getBanlanceFactor(node) < -1) {
// 树整体向右倾斜, 需要左旋, 同理, 也要考虑上面那种情况
if (getBanlanceFactor(node.right) > 0) {
node.rightt = rightRotate(node.right);
}
node = leftRotate(node);
}
return ret
}
}
// 查找某个node, 整体和add很相似
private Node getNode(K key) {
if (key.compareTo(node.key) > 0) {
return getNode(node.right, key)
}else if (key.compareTo(node.key) < 0) {
return getNode(node.left, key)
}else {
return node;
}
}
// 找到节点的后继节点
private Node minimum(Node node) {
while (node.left != null) {
node = node.left;
}
return node;
}
// 查看是否包含某个key
public boolean contains(K key) {
return contains(root, key)
}
private boolean contains(Node node, K key) {
if (node == null) {
return false;
}
if (key.compareTo(node.key) > 0) {
return contains(node.right, key)
}else if (key.compareTo(node.key) < 0) {
return contains(node.left, key)
}else {
return true;
}
}
}