红黑树
2-3树
2-3树的节点它可以有一个元素,也可以有两个元素,它也满足二分搜索树的性质
我们把含有两个孩子的节点称为2节点,含有3个孩子的节点称为3节点
2-3树是一种绝对平衡的树,所谓绝对平衡的树指的是从根节点到任意一个叶子节点,所经过的节点是都是相同的。那么2-3树是怎么做到的呢?
红黑树与2-3树的等价性
由于我们一般每个节点都是表示一个数据的,2-3树有点难以实现,所以有人发明一种树叫做红黑树,它可以说是2-3树的等价,那么它树如何等价的呢?
上图想必很清楚的描述了等价的过程
现在我们来实现一下上面描述的红黑树,大部分的代码都是和二分搜索树是重合的,只是在添加时有调整,另外这里我们不牵涉到从红黑树中删除元素,因为太复杂了(其实是我不会)
public class RedBlackTree<E extends Comparable<E>> {//规定红色为true 黑色为falseprivate static final boolean RED = true;private static final boolean BLACK = false;private class Node {public E e;public Node left;public Node right;public boolean color;public Node(E e) {this.e = e;left = null;right = null;//我们在2-3树中添加节点时 永远是和别的节点融合 所以默认为红色color = RED;}@Overridepublic String toString() {return e.toString();}}private Node root;private int size;public RedBlackTree() {root = null;size = 0;}public int size() {return size;}public boolean isEmpty() {return size == 0;}public void add(E e) {root = add(root, e);}// 判断节点node的颜色private boolean isRed(Node node){if(node == null)return BLACK;return node.color;}private Node add(Node node, E e) {if (node == null) {size++;return new Node(e);}if (e.compareTo(node.e) < 0) {node.left = add(node.left, e);} else if (e.compareTo(node.e) > 0) {node.right = add(node.right,e);}return node;}public boolean contains(E e) {return contains(root, e);}private boolean contains(Node node, E e) {if (node == null) {return false;}if (e.equals(node.e)) {return true;} else if (e.compareTo(node.e) < 0) {return contains(node.left, e);} else {return contains(node.right,e);}}}
红黑树的性质
在了解了红黑树与2-3等价以后,我们来看红黑树满足哪些性质
- 每个节点或者是红色的,或者的是黑色的
- 根节点是黑色的

- 每一个叶子节点(最后的空节点是黑色的)
- 因为红色节点只存在于3节点中,而所有的叶子节点都是2节点
- 如果一个节点是红色的,那么它的所有孩子节点都是黑色的

- 从任意一个节点到黑色节点,经过的黑色节点是一样的
- 因为2-3树到所有叶子节点的距离都是一样的,而经过的节点,不管是2节点还是3节点,都包括一个黑色节点,所以经过的黑色节点是一样的
向红黑树中添加元素
因为根节点是黑色的,所以我们在添加完元素后需要将根节点变为黑色
public void add(E e) {root = add(root, e);root.color = BLACK;}
在添加元素到红黑树中时,可能会破坏红黑树的规则,这时就需要红黑树进行自我调整,我们就来看一下添加过程会碰到的所有情形,以及处理方法
// node x// / \ 左旋转 / \// T1 x ---------> node T3// / \ / \// T2 T3 T1 T2private Node leftRotate(Node node){Node x = node.right;// 左旋转node.right = x.left;x.left = node;x.color = node.color;node.color = RED;return x;}

// 颜色翻转private void flipColors(Node node){node.color = RED;node.left.color = BLACK;node.right.color = BLACK;}

// node x// / \ 右旋转 / \// x T2 -------> y node// / \ / \// y T1 T1 T2private Node rightRotate(Node node){Node x = node.left;// 右旋转node.left = x.right;x.right = node;x.color = node.color;node.color = RED;return x;}

对上面的情况进行总结
private Node add(Node node, E e) {if (node == null) {size++;return new Node(e);}if (e.compareTo(node.e) < 0) {node.left = add(node.left, e);} else if (e.compareTo(node.e) > 0) {node.right = add(node.right,e);}if (isRed(node.right) && !isRed(node.left))node = leftRotate(node);if (isRed(node.left) && isRed(node.left.left))node = rightRotate(node);if (isRed(node.left) && isRed(node.right))flipColors(node);return node;}
完整代码
public class RedBlackTree<E extends Comparable<E>> {//规定红色为true 黑色为falseprivate static final boolean RED = true;private static final boolean BLACK = false;private class Node {public E e;public Node left;public Node right;public boolean color;public Node(E e) {this.e = e;left = null;right = null;//我们在2-3树中添加节点时 永远是和别的节点融合 所以默认为红色color = RED;}@Overridepublic String toString() {return e.toString();}}private Node root;private int size;public RedBlackTree() {root = null;size = 0;}public int size() {return size;}public boolean isEmpty() {return size == 0;}private boolean isRed(Node node) {if (node == null) {return BLACK;}return node.color;}// node x// / \ 左旋转 / \// T1 x ---------> node T3// / \ / \// T2 T3 T1 T2private Node leftRotate(Node node) {Node x = node.right;node.right = x.left;x.left = node;x.color = node.color;node.color = RED;return x;}// node x// / \ 右旋转 / \// x T2 -------> y node// / \ / \// y T1 T1 T2private Node rightRotate(Node node) {Node x = node.left;node.left = x.right;x.right = node;x.color = node.color;node.color = RED;return x;}private void flipColors(Node node) {node.color = RED;node.left.color = BLACK;node.right.color = BLACK;}public void add(E e) {root = add(root, e);root.color = BLACK;}private Node add(Node node, E e) {if (node == null) {size++;return new Node(e);}if (e.compareTo(node.e) < 0) {node.left = add(node.left, e);} else if (e.compareTo(node.e) > 0) {node.right = add(node.right,e);}if (isRed(node.right) && !isRed(node.left))node = leftRotate(node);if (isRed(node.left) && isRed(node.left.left))node = rightRotate(node);if (isRed(node.left) && isRed(node.right))flipColors(node);return node;}public boolean contains(E e) {return contains(root, e);}private boolean contains(Node node, E e) {if (node == null) {return false;}if (e.equals(node.e)) {return true;} else if (e.compareTo(node.e) < 0) {return contains(node.left, e);} else {return contains(node.right,e);}}}
