读者盆友,晚上好。
本博客代码示例均来自:算法 Algorithmes Forth Edition
[美] Robert Sedgewick Kevin Wayne 著 谢路云译
前几篇博客顺序的介绍了符号表的各种实现:
我们首先介绍了:无序链表中顺序查找 -》 有序数组中的二分查找
二分查找优缺点:
二分查找 | 优点 | 缺点 |
---|---|---|
查找非常快,已知的最快的方法,复杂度在log N | 静态的、有序的数据,无法应对动态插入的数据 |
接着:为了找到克服二分法缺点算法,介绍了二叉查找树,这种数可以支持动态插入,同时它的key还能保持有序(可用二分法查),我们已经前进了一大步,然而二叉查找树也有缺点。
二叉查找树 | 优点 | 缺点 |
---|---|---|
支持动态插入数据,同时还能用二分法根据Key快速查找 | 最坏情况搜索路径上会出现N个节点 |
因此,我们继续寻找看是否还有克服了二叉查找树最坏情况的算法。
可喜的是,我们找到了:平衡查找树
平衡查找树能时刻保证“平衡”,所以会避免二叉查找树最坏的情况,同时又兼有之前优化后的各种优点,堪称完美。
不过因为平衡二叉树引入了4-节点等概念,为了简化代码,出现了红黑二叉查找树,这种树 简单来说可以和 平衡查找树 “等价”,又可以避免4-节点的操作。所以,这是我们最终想要找到的。
平衡查找树 | 优点 | 缺点 |
---|---|---|
始终平衡,避免了二叉查找树最坏情况搜索路径上会出现N个节点的情况 | 代码复杂,不好理解 |
好了,最终上今天的代码:
package com.cmh.algorithm;
import static edu.princeton.cs.algs4.StdIn.isEmpty;
/**
* Author:起舞的日子
* ate: 2020/4/12 下午10:12
* 红黑树的插入算法
*/
public class RedBlackBST<Key extends Comparable<Key>, Value> {
public static final boolean RED = true;
private static final boolean BLACK = false;
private Node root;
private boolean isRed(Node h) {
if (h == null) {
return false;
}
return h.color;
}
private Node rotateLeft(Node h) {
Node x = h.right;
h.right = x.left;
x.left = h;
x.color = h.color;
h.color = RED;
x.N = h.N;
h.N = 1 + size(h.left) + size(h.right);
return x;
}
private Node rotateRight(Node h) {
Node x = h.left;
h.left = x.right;
x.right = h;
x.color = h.color;
h.color = RED;
x.N = h.N;
h.N = 1 + size(h.left) + size(h.right);
return x;
}
private void flipColors(Node h) {
h.color = RED;
h.left.color = BLACK;
h.right.color = BLACK;
}
private int size() {
return size(root);
}
private int size(Node x) {
if (x == null) {
return 0;
} else {
return x.N;
}
}
private Node put(Node h, Key key, Value val) {
/*
标准的插入操作,和父节点用红链接相连
*/
if (h == null) {
return new Node(key, val, 1, RED);
}
int cmp = key.compareTo(h.key);
if (cmp < 0) {
h.left = put(h.left, key, val);
} else if (cmp > 0) {
h.right = put(h.right, key, val);
} else {
h.val = val;
}
if (isRed(h.right) && !isRed(h.left)) {
h = rotateLeft(h);
}
if (isRed(h.left) && isRed(h.left.left)) {
h = rotateRight(h);
}
if (isRed(h.left) && isRed(h.right)) {
flipColors(h);
}
return h;
}
/**
* 删除最小键
*/
private Node moveRedLeft(Node h) {
/*
假设h结点为红色,h.left和h.left.left都是黑色
将h.left或者h.left的子结点之一变红
*/
flipColors(h);
if (isRed(h.right.left)) {
h.right = rotateRight(h.right);
h = rotateLeft(h);
}
return h;
}
private Node deleteMin(Node h) {
if (h.left == null) {
return null;
}
if (!isRed(h.left) && !isRed(h.left.left)) {
h = moveRedLeft(h);
}
h.left = deleteMin(h.left);
return balance(h);
}
private Node balance(Node h) {
if (isRed(h.right)) {
rotateLeft(h);
}
if (isRed(h.left) && isRed(h.left.left)) {
h = rotateRight(h);
}
if (isRed(h.left) && isRed(h.right)) {
flipColors(h);
}
return h;
}
public void deleteMin() {
if (!isRed(root.left) && !isRed(root.right)) {
root.color = RED;
}
root = deleteMin(root);
if (!isEmpty()) {
root.color = BLACK;
}
}
/**
* 删除最大键
*/
private Node moveRedRight(Node h) {
/*
假设结点h为红色,h.right和h.right.left都是黑色
将h.right或者h.right的子结点之一变红
*/
flipColors(h);
if (!isRed(h.left.left)) {
h = rotateRight(h);
}
return h;
}
private Node deleteMax(Node h) {
if (isRed(h.left)) {
h = rotateRight(h);
}
if (h.right == null) {
return null;
}
if (!isRed(h.right) && !isRed(h.right.left)) {
h = moveRedRight(h);
}
h.right = deleteMax(h.right);
return balance(h);
}
public void deleteMax() {
if (!isRed(root.left) && !isRed(root.right)) {
root.color = RED;
}
root = deleteMax(root);
if (!isEmpty()) {
root.color = BLACK;
}
}
/**
* 红黑树最终的删除操作
*/
private Node delete(Node h, Key key) {
if (key.compareTo(h.key) < 0) {
if (!isRed(h.left) && !isRed(h.left.left)) {
h = moveRedLeft(h);
}
h.left = delete(h.left, key);
} else {
if (isRed(h.left)) {
h = rotateRight(h);
}
if (key.compareTo(h.key) == 0 && (h.right == null)) {
return null;
}
if (!isRed(h.right) && !isRed(h.right.left)) {
h = moveRedRight(h);
}
if (key.compareTo(h.key) == 0) {
h.val = get(h.right, min(h.right).key);
h.key = min(h.right).key;
h.right = deleteMin(h.right);
} else {
h.right = delete(h.right, key);
}
}
return balance(h);
}
public Value get(Key key) {
return get(root, key);
}
private Value get(Node x, Key key) {
if (x == null) {
return null;
}
int cmp = key.compareTo(x.key);
if (cmp < 0) {
return get(x.left, key);
} else if (cmp > 0) {
return get(x.right, key);
} else {
return x.val;
}
}
public Key min() {
return min(root).key;
}
private Node min(Node x) {
if (x.left == null) {
return x;
}
return min(x.left);
}
private class Node {
/**
* key:键
* val:值
* left right左右子树
* N 这棵子树中的结点总数
* color 由其父节点指向它的链接的颜色
*/
Key key;
Value val;
Node left, right;
int N;
boolean color;
Node(Key key, Value val, int N, boolean color) {
this.key = key;
this.val = val;
this.N = N;
this.color = color;
}
private boolean isRed(Node x) {
if (x == null) {
return false;
}
return x.color;
}
}
}
嗯,下次再会!