关于红黑树

hashmap中的处理有红黑树的参与,我了解了一下红黑树

红黑树 并不追求“完全平衡 ”——它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能。

红黑树能够以 O(log2 n) 的时间复杂度进行搜索、插入、删除操作。此外,由于它的设计,任何不平衡都会在三次旋转之内解决。当然,还有一些更好的,但实现起来更复杂的数据结构 能够做到一步旋转之内达到平衡,但红黑树能够给我们一个比较“便宜”的解决方案。红黑树的算法时间复杂度和AVL相同,但统计性能比AVL树更高。

当然,红黑树并不适应所有应用树的领域。如果数据基本上是静态的,那么让他们待在他们能够插入,并且不影响平衡的地方会具有更好的性能。如果数据完全是静态的,例如,做一个哈希表,性能可能会更好一些。

接下来,用Java完成了添加和删除操作:

基础:
* 对红黑树的节点(x)进行左旋转
*
* 左旋示意图(对节点x进行左旋):
* root root
* / /
* x p
* / \ --(左旋)-. /
* lx p x rp
* / \ /
* lp rp lx lp
*
*
*/
private <K,V extends Comparable<V>> void rightRotate(TreeNode<K,V> x, TreeNode<K,V> root){
TreeNode<K,V> p=x.right;
if(p.left!=null){
x.right=p.left;
}
if(p.left!=null){
p.left.parent=x;
}
if (x.parent == null) {
root=p;//x为根节点的时候
} else {
if (x.parent.left == x)
x.parent.left = p;
else
x.parent.right = p;
}
p.left=x;
x.parent=p;
}

右旋:
/*

  • 对红黑树的节点(x)进行右旋转
  • 右旋示意图(对节点x进行左旋):
  •        py                               py
    
  •       /                                /
    
  •      x                               p
    
  •     /  \      --(右旋)-.>>          /  \
    
  •    p   rx                           lp   x
    
  •   / \                                   / \
    
  •  lp  rp                                rp  rx
    

*/
private <K,V extends Comparable<V>> void leftRotate(TreeNode<K,V> x,TreeNode<K,V> root){
TreeNode<K,V> p=x.right;
if(p.right!=null){
x.left=p.right;
}
if(p.right!=null){
p.right.parent=x;
}
if (x.parent == null) {
root=p;//x为根节点的时候
} else {
if (x.parent.right == x)
x.parent.left = p;
else
x.parent.right = p;
}
p.left=x;
x.parent=p;
}
}

插入:

 * 1.将红黑树当做一颗二叉树,将节点插入
 * 2.将节点的颜色变为红色
 * 3.接下来就是调整使其成为红黑树
 *红黑树的特点:
 *每个节点或者是黑色,或者是红色。
 *根节点是黑色。
 *每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!]
 *如果一个节点是红色的,则它的子节点必须是黑色的。
 * 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
 * @param n
 * @param root 根节点
 * @param <K>
 * @param <V>
 */
private   <K,V extends Comparable<V>> void  insert(TreeNode<K,V> n,TreeNode<K,V> root){
    while (root != null) {
        if (n.key.compareTo(root.key) < 0)
            root =root.left;
        else
            root= root.right;
    }
    TreeNode<K, V> p=null;
    if(root==null){
        root=n;
    }else {
         p = root.parent;
    }
    n.parent=p;
    n.red=true;
    //加节点
    if(n.key.compareTo(p.key)>0){
        p.right=n;
    }else {
        p.left=n;
    }
    insertRedTree(n,root);
}

private  <K, V extends Comparable<V>> void insertRedTree(TreeNode<K, V> n,TreeNode<K, V> root) {
    TreeNode<K, V> parent=n.parent;
    //是根节点直接将颜色变为黑色
    if(n.parent==null){
        n.red=false;
    }
    while((parent=n.parent)!=null&&parent.red){

        TreeNode<K, V> gParent=n.parent.parent;
        //当前节点的父节点与其兄弟节点都为红色的时候
        if(gParent.left.red&&gParent.right.red||(gParent.left.red&&gParent.right!=null)||(gParent.right.red&&gParent.left!=null)){
            gParent.right.red=false;
            gParent.left.red=false;
            gParent.red=true;
            n=gParent;
            continue;
        }
        //其兄弟节点是黑色,且当前节点是右孩子
        if(n==parent.right){
            n=parent;
            parent=n.parent;
            n.leftRotate(n,root);

        }else{
            //其兄弟节点是黑色,且当前节点是左孩子
            parent.red=false;
            gParent.red=true;
            n.rightRotate(gParent,root);

        }
    }
    root.red=false;
}

删除:

private <K, V extends Comparable<V>> void remove(TreeNode<K, V> n,TreeNode<K, V> root){
TreeNode<K, V> child, parent;
if(n.left!=null&&n.right!=null){
//被删除节点有两个儿子。
// 那么,先找出它的后继节点;
// 然后把“它的后继节点的内容”复制给“该节点的内容”;
// 之后,删除“它的后继节点”。
// 在这里,后继节点相当于替身,
// 在将后继节点的内容复制给"被删除节点"之后,
// 再将后继节点删除。这样就巧妙的将问题转换为"删除后继节点"的情况了.
TreeNode<K, V> replace = n;
// 获取后继节点
replace = replace.right;
while(replace.left!=null){
replace=replace.left;
}
/**
*
* O
* /
* x y
* /
* p rx
* / \ /
* lp rp a b
*
* x的后继结点是a
*/
if(n.parent==null){
root=replace;
}else {
if(n.parent.left==n){
n.parent.left=replace;
}else {
n.parent.right = replace;
}
}
child=replace.right;
parent=replace.parent;
boolean color=replace.red;
//将后继节点覆盖删除的值,将后继节点的right接到parent上
if(parent==n){
parent=replace;
}else{
if(child!=null){
child.parent=parent;
parent.left=child;
replace.right=n.right;
n.right.parent=replace;
}
}
//属性全部替代
replace.parent = n.parent;
replace.red = n.red;
replace.left = n.left;
n.left.parent = replace;
//如果原先颜色是黑色的
if(!color){
//维持红黑树的特性
removeRedTree(child, parent,root);
}
n=null;
return;
}

    //被删除节点只有一个儿子。那么,直接删除该节点,并用该节点的唯一子节点顶替它的位置。
    if (n.left !=null) {
        child = n.left;
    } else {
        child = n.right;
    }

    parent = n.parent;
    // 保存"取代节点"的颜色
     boolean color = n.red;

    if (child!=null)
        child.parent = parent;

    // "node节点"不是根节点
    if (parent!=null) {
        if (parent.left == n)
            parent.left = child;
        else
            parent.right = child;
    } else {
        root = child;
    }

    if (color == false)
        removeRedTree(child, parent,root);
       n = null;


}

private <K, V extends Comparable<V>> void removeRedTree(TreeNode<K, V> n, TreeNode<K, V> parent, TreeNode<K, V> root) {
    TreeNode<K,V> p;
    while((n==null||n.red)&&n.parent!=null) {
        if (parent.left == n)
            p = parent.right;
        else p=parent.left;
            //x是“黑+黑”节点,x的兄弟节点是红色。
            if (p.red) {
                p.red=false;
                parent.red=true;
                p.leftRotate(parent,root);
                p= parent.right;
            }
            // x是“黑+黑”节点,x的兄弟节点是黑色,x的兄弟节点的两个孩子都是黑色。
            if ((p.left==null || !p.left.red) &&
                    (p.right==null || !p.right.red)) {
                p.red=true;
                n = parent;
                parent = n.parent;
            }
            else {
                //x是“黑+黑”节点,x的兄弟节点是黑色;x的兄弟节点的左孩子是红色,右孩子是黑色的。
                if (p.right==null || !(p.right.red)) {
                    p.left.red=false;
                    p.red=true;
                    p.rightRotate(p,root);
                    p = parent.right;
                }
                //x是“黑+黑”节点,x的兄弟节点是黑色;x的兄弟节点的右孩子是红色的,x的兄弟节点的左孩子任意颜色。
                p.red=p.parent.red;
                p.parent.red=false;
                p.right.red=false;
                p.leftRotate(parent,root);
                n=root;
                break;
            }

    }

}

此文参考了网上的实现
读源码,是我们了解大神领域的一大捷径
生命不息,奋斗不止

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,660评论 0 33
  • 1. AVL树 AVL树简单来说是带有平衡条件的二叉查找树.传统来说是其每个节点的左子树和右子树的高度最多差1(注...
    fredal阅读 1,790评论 0 4
  • 一、基本数据类型 注释 单行注释:// 区域注释:/* */ 文档注释:/** */ 数值 对于byte类型而言...
    龙猫小爷阅读 4,213评论 0 16
  • 其实我很早就想写一些东西,只是忽然发现自己很久不曾动过笔渐渐的有些忘却了如何去写,但是脑海里总是闪现着一...
    MR丶罗先森阅读 479评论 3 3
  • 冬季冰城的夜并没有想象的那样美好,被冰雪覆盖着,用东北人讲话:嘎嘎冷。 孙二娃进城做快递也满一个月了,这是他活到十...
    泥腿看客阅读 451评论 0 1