红黑树的性质
红黑树是一课二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,可以使RED或BLACK。通过对任何一条从根到叶子的简单路径上各个结点的颜色进行约束,红黑树确保没有一条路径会比其他路径长出2倍,因而是近似平衡的。
树中每个结点包含5个属性:color、key、left、right、parent。如果一个结点没有子结点或父结点,则该结点相应属性的值为null。一棵红黑树是满足下面红黑性质的二叉搜索树:
- 每个结点或是红色的,或是黑色的;
- 根结点是黑色的;
- 每个叶结点是黑色的;
- 如果一个结点是红色的,则它的两个子结点都是黑色的;
- 对每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点。
为了便于处理红黑树代码中的边界条件,可以使用一个哨兵来代表null。对于一棵红黑树,哨兵是一个与树中的普通结点有相同属性的对象。它的color属性为BLACK,其他属性可以设置为任意值。如下图所示为一棵使用了哨兵的红黑树示例。
旋转
当对树执行插入或操作时,对树做了修改,所做的修改可能会导致树不满足红黑树的性质,因此需要进行旋转来维护红黑树的性质。旋转可分为左旋和右旋。下图展示了一棵子树旋转后的结果。
java代码实现
下面是使用java简单实现了红黑树,以及红黑树的插入和删除操作。
/*** 数据结构-红黑树*/
public class RBTree {/*** 哨兵*/private final Node sentinel = new Node(Color.BLACK);/*** 根节点*/private Node root = sentinel;/*** 根据关键字搜索节点** @param key 关键字* @return key所在的节点*/public Node search(int key) {Node node = root;while (node != null && key != node.key) {// 如果key小于当前节点的key,则往左孩子节点找,否则往右孩子节点找if (key < node.key) {node = node.left;} else {node = node.right;}}return node;}/*** 插入关键字为key的节点** @param key 关键字*/public void insert(int key) {Node y = sentinel;Node x = root;while (x != sentinel) {y = x;if (key < x.key) {x = x.left;} else {x = x.right;}}Node newNode = new Node();newNode.key = key;newNode.parent = y;if (y == sentinel) {root = newNode;} else if (key < y.key) {y.left = newNode;} else {y.right = newNode;}newNode.left = sentinel;newNode.right = sentinel;newNode.color = Color.RED;insertFixUp(newNode);}/*** 删除关键字为key的节点** @param key 关键字*/public void delete(int key) {Node node = search(key);Node y = node;Color yOriginalColor = y.color;Node x;if (node.left == sentinel) {x = node.right;transplant(node, node.right);} else if (node.right == sentinel) {x = node.left;transplant(node, node.left);} else {y = min(node.right);yOriginalColor = y.color;x = y.right;if (y.parent == node) {x.parent = y;} else {transplant(y, y.right);y.right = node.right;y.right.parent = y;}transplant(node, y);y.left = node.left;y.left.parent = y;y.color = node.color;}if (yOriginalColor == Color.BLACK) {deleteFixUp(x);}}/*** 获取以node为根的子树中key最小的节点** @param node 子树根节点* @return 子树中key最小的节点*/public Node min(Node node) {while (node.left != null) {node = node.left;}return node;}public Node getRoot() {return root;}/*** 删除一个节点后,维护树的红黑性质** @param node 节点*/private void deleteFixUp(Node node) {while (node != root && node.color == Color.BLACK) {if (node == node.parent.left) {Node w = node.parent.right;if (w.color == Color.RED) {w.color = Color.BLACK;node.parent.color = Color.RED;leftRotate(node.parent);w = node.parent.right;}if (w.left.color == Color.BLACK && w.right.color == Color.BLACK) {w.color = Color.RED;node = node.parent;} else if (w.right.color == Color.BLACK) {w.left.color = Color.BLACK;w.color = Color.RED;rightRotate(w);w = node.parent.right;}w.color = node.parent.color;node.parent.color = Color.BLACK;w.right.color = Color.BLACK;leftRotate(node.parent);node = root;} else {Node w = node.parent.left;if (w.color == Color.RED) {w.color = Color.BLACK;node.parent.color = Color.RED;leftRotate(node.parent);w = node.parent.left;}if (w.right.color == Color.BLACK && w.left.color == Color.BLACK) {w.color = Color.RED;node = node.parent;} else if (w.left.color == Color.BLACK) {w.right.color = Color.BLACK;w.color = Color.RED;leftRotate(w);w = node.parent.left;}w.color = node.parent.color;node.parent.color = Color.BLACK;w.left.color = Color.BLACK;rightRotate(node.parent);node = root;}}node.color = Color.BLACK;}/*** 将node1替换成node2,以支持删除操作** @param node1 节点1* @param node2 节点2*/private void transplant(Node node1, Node node2) {if (node1.parent == sentinel) {root = node2;} else if (node1 == node1.parent.left) {node1.parent.left = node2;} else {node1.parent.right = node2;}node2.parent = node1.parent;}/*** 插入一个节点后,维护树的红黑性质** @param node 插入的节点*/private void insertFixUp(Node node) {while (node.parent.color == Color.RED) {if (node.parent == node.parent.parent.left) {Node temp = node.parent.parent.right;if (temp.color == Color.RED) {node.parent.color = Color.BLACK;temp.color = Color.BLACK;node.parent.parent.color = Color.RED;node = node.parent.parent;} else if (node == node.parent.right) {node = node.parent;leftRotate(node);} else {node.parent.color = Color.BLACK;node.parent.parent.color = Color.RED;rightRotate(node.parent.parent);}} else {Node temp = node.parent.parent.left;if (temp.color == Color.RED) {node.parent.color = Color.BLACK;temp.color = Color.BLACK;node.parent.parent.color = Color.RED;node = node.parent.parent;} else if (node == node.parent.left) {node = node.parent;rightRotate(node);} else {node.parent.color = Color.BLACK;node.parent.parent.color = Color.RED;leftRotate(node.parent.parent);}}}root.color = Color.BLACK;}/*** 在节点node上进行左旋操作** @param node 节点*/private void leftRotate(Node node) {Node right = node.right;// 将node的右子树的左子树放到node的右子树位置node.right = right.left;if (right.left != sentinel) {right.left.parent = node;}// 设置node的右子树的父节点为node的父节点right.parent = node.parent;if (node.parent == sentinel) {root = right;} else if (node == node.parent.left) {node.parent.left = right;} else {node.parent.right = right;}// 将node放到node的右子树的左子树位置right.left = node;node.parent = right;}/*** 在节点node上进行右旋操作** @param node 节点*/private void rightRotate(Node node) {Node left = node.left;node.left = left.right;if (left.right != sentinel) {left.right.parent = node;}left.parent = node.parent;if (node.parent == sentinel) {root = left;} else if (node == node.parent.right) {node.parent.right = left;} else {node.parent.left = left;}left.right = node;node.parent = left;}private enum Color {/*** 红色*/RED,/*** 黑色*/BLACK}public static class Node {/*** 节点颜色*/private Color color;/*** 节点关键字*/private int key;/*** 左孩子节点*/private Node left;/*** 右孩子节点*/private Node right;/*** 父节点*/private Node parent;private Node() {}private Node(Color color) {this.color = color;}public Color getColor() {return color;}public int getKey() {return key;}public Node getLeft() {return left;}public Node getRight() {return right;}public Node getParent() {return parent;}}
}