红黑树

来源:互联网 发布:学乐器的软件 编辑:程序博客网 时间:2024/06/10 18:05

红黑树介绍

红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树。
红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键值,小于等于右孩子的键值。
除了具备该特性之外,红黑树还包括许多额外的信息。

红黑树的每个节点上都有存储位表示节点的颜色,颜色是红(Red)或黑(Black)。
红黑树的特性:
(1) 每个节点或者是黑色,或者是红色。
(2) 根节点是黑色。
(3) 每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!]
(4) 如果一个节点是红色的,则它的子节点必须是黑色的。
(5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

关于它的特性,需要注意的是:
第一,特性(3)中的叶子节点,是只为空(NIL或null)的节点。
第二,特性(5),确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树。

红黑树的应用比较广泛,主要是用它来存储有序的数据,它的时间复杂度是O(lgn),效率非常之高。
这里写图片描述

红黑树的操作

红黑树的基本操作是添加、删除和旋转。在对红黑树进行添加或删除后,会用到旋转方法。为什么呢?道理很简单,添加或删除红黑树中的节点之后,红黑树就发生了变化,可能不满足红黑树的5条性质,也就不再是一颗红黑树了,而是一颗普通的树。而通过旋转,可以使这颗树重新成为红黑树。简单点说,旋转的目的是让树保持红黑树的特性。
旋转包括两种:左旋 和 右旋。

红黑树节点的的定义

Java实现

 public class RBTNode<T extends Comparable<T>> {    boolean color;        // 颜色    T key;                // 关键字(键值)    RBTNode<T> left;    // 左孩子    RBTNode<T> right;    // 右孩子    RBTNode<T> parent;    // 父结点    public RBTNode(T key, boolean color, RBTNode<T> parent, RBTNode<T> left, RBTNode<T> right) {        this.key = key;        this.color = color;        this.parent = parent;        this.left = left;        this.right = right;    }}

左旋

这里写图片描述
对x进行左旋,意味着”将x变成一个左节点”。

private void leftRotate(RBTNode<T> x) {    // 设置x的右孩子为y    RBTNode<T> y = x.right;    // 将 “y的左孩子” 设为 “x的右孩子”;    // 如果y的左孩子非空,将 “x” 设为 “y的左孩子的父亲”    x.right = y.left;    if (y.left != null)        y.left.parent = x;    // 将 “x的父亲” 设为 “y的父亲”    y.parent = x.parent;    if (x.parent == null) {        this.mRoot = y;            // 如果 “x的父亲” 是空节点,则将y设为根节点    } else {        if (x.parent.left == x)            x.parent.left = y;    // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子”        else            x.parent.right = y;    // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子”    }    // 将 “x” 设为 “y的左孩子”    y.left = x;    // 将 “x的父节点” 设为 “y”    x.parent = y;}

右旋

这里写图片描述

private void rightRotate(RBTNode<T> y) {    // 设置x是当前节点的左孩子。    RBTNode<T> x = y.left;    // 将 “x的右孩子” 设为 “y的左孩子”;    // 如果"x的右孩子"不为空的话,将 “y” 设为 “x的右孩子的父亲”    y.left = x.right;    if (x.right != null)        x.right.parent = y;    // 将 “y的父亲” 设为 “x的父亲”    x.parent = y.parent;    if (y.parent == null) {        this.mRoot = x;            // 如果 “y的父亲” 是空节点,则将x设为根节点    } else {        if (y == y.parent.right)            y.parent.right = x;    // 如果 y是它父节点的右孩子,则将x设为“y的父节点的右孩子”        else            y.parent.left = x;    // (y是它父节点的左孩子) 将x设为“x的父节点的左孩子”    }    // 将 “y” 设为 “x的右孩子”    x.right = y;    // 将 “y的父节点” 设为 “x”    y.parent = x;}
原创粉丝点击