关于红黑树的左旋右旋

Posted 开源java学习

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于红黑树的左旋右旋相关的知识,希望对你有一定的参考价值。


刚刚看篇文章,是讲清华毕业去面试被面试官各种嫌弃,..放网了。认为红黑树都不会写居然应届毕业要18k...


 

红-黑树的特征

  有如下两个特征:

  ①、节点都有颜色;

  ②、在插入和删除的过程中,要遵循保持这些颜色的不同排列规则。


  第一个很好理解,在红-黑树中,每个节点的颜色或者是黑色或者是红色的。当然也可以是任意别的两种颜色,这里的颜色用于标记,我们可以在节点类Node中增加一个boolean型变量isRed,以此来表示颜色的信息。


  第二点,在插入或者删除一个节点时,必须要遵守的规则称为红-黑规则:

  1.每个节点不是红色就是黑色的;

  2.根节点总是黑色的;


  3.如果节点是红色的,则它的子节点必须是黑色的(反之不一定),(也就是从每个叶子到根的所有路径上不能有两个连续的红色节点);


  4.从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)。


  从根节点到叶节点的路径上的黑色节点的数目称为黑色高度,规则 4 另一种表示就是从根到叶节点路径上的黑色高度必须相同。

关于红黑树的左旋右旋

  注意:新插入的节点颜色总是红色的,这是因为插入一个红色节点比插入一个黑色节点违背红-黑规则的可能性更小,原因是插入黑色节点总会改变黑色高度(违背规则4),但是插入红色节点只有一半的机会会违背规则3(因为父节点是黑色的没事,父节点是红色的就违背规则3)。另外违背规则3比违背规则4要更容易修正。当插入一个新的节点时,可能会破坏这种平衡性,那么红-黑树是如何修正的呢?


2、红-黑树的自我修正

  红-黑树主要通过三种方式对平衡进行修正,改变节点颜色、左旋和右旋。

  ①、改变节点颜色

  新插入的节点为15,一般新插入颜色都为红色,那么我们发现直接插入会违反规则3,改为黑色却发现违反规则4。这时候我们将其父节点颜色改为黑色,父节点的兄弟节点颜色也改为黑色。通常其祖父节点50颜色会由黑色变为红色,但是由于50是根节点,所以我们这里不能改变根节点颜色。

  ②、右旋

  首先要说明的是节点本身是不会旋转的,旋转改变的是节点之间的关系,选择一个节点作为旋转的顶端,如果做一次右旋,这个顶端节点会向下和向右移动到它右子节点的位置,它的左子节点会上移到它原来的位置。右旋的顶端节点必须要有左子节点。

关于红黑树的左旋右旋

  ③、左旋

  左旋的顶端节点必须要有右子节点。

关于红黑树的左旋右旋   

注意:我们改变颜色也是为了帮助我们判断何时执行什么旋转,而旋转是为了保证树的平衡。光改变节点颜色是不能起到任何作用的,旋转才是关键的操作,在新增节点或者删除节点之后,可能会破坏二叉树的平衡,那么何时执行旋转以及执行什么旋转,这才是要点。


3、左旋和右旋代码

①、节点

  节点类和二叉树的节点类差不多,只不过在其基础上增加了一个 boolean 类型的变量来表示节点的颜色。

public class RBNode<T extends Comparable<T>> {

    boolean color;//颜色

    T key;//关键值

    RBNode<T> left;//左子节点

    RBNode<T> right;//右子节点

    RBNode<T> parent;//父节点

     

    public RBNode(boolean color,T key,RBNode<T> parent,RBNode<T> left,RBNode<T> right){

        this.color = color;

        this.key = key;

        this.parent = parent;

        this.left = left;

        this.right = right;

    }

     

    //获得节点的关键值

    public T getKey(){

        return key;

    }

    //打印节点的关键值和颜色信息

    public String toString(){

        return ""+key+(this.color == RED ? "R":"B");

    }

}

②、左旋的具体实现

/********对红黑树节点x进行左旋操作 ************/

/* 

 * 左旋示意图:对节点x进行左旋 

 *     p                       p 

 *    /                       / 

 *   x                       y 

 *  /                      /  

 * lx  y      ----->       x  ry 

 *    /                  /  

 *   ly ry               lx ly 

 * 左旋做了三件事: 

 * 1. 将y的左子节点赋给x的右子节点,并将x赋给y左子节点的父节点(y左子节点非空时) 

 * 2. 将x的父节点p(非空时)赋给y的父节点,同时更新p的子节点为y(左或右) 

 * 3. 将y的左子节点设为x,将x的父节点设为y 

 */

private void leftRotate(RBNode<T> x){

    //1. 将y的左子节点赋给x的右子节点,并将x赋给y左子节点的父节点(y左子节点非空时)

    RBNode<T> y = x.right;

    x.right = y.left;

    if(y.left != null){

        y.left.parent = x;

    }

     

    //2. 将x的父节点p(非空时)赋给y的父节点,同时更新p的子节点为y(左或右)

    y.parent = x.parent;

    if(x.parent == null){

        this.root = y;//如果x的父节点为空(即x为根节点),则将y设为根节点

    }else{

        if(x == x.parent.left){//如果x是左子节点

            x.parent.left = y;//则也将y设为左子节点 

        }else{

            x.parent.right = y;//否则将y设为右子节点 

        }

    }

     

    //3. 将y的左子节点设为x,将x的父节点设为y

    y.left = x;

    x.parent = y;

}


③、右旋的具体实现  


/*******对红黑树节点y进行右旋操作 **********/ 

/*

 * 左旋示意图:对节点y进行右旋

 *        p                   p

 *       /                   /

 *      y                   x

 *     /                  /

 *    x  ry   ----->      lx  y

 *   /                      /

 * lx  rx                   rx ry

 * 右旋做了三件事:

 * 1. 将x的右子节点赋给y的左子节点,并将y赋给x右子节点的父节点(x右子节点非空时)

 * 2. 将y的父节点p(非空时)赋给x的父节点,同时更新p的子节点为x(左或右)

 * 3. 将x的右子节点设为y,将y的父节点设为x

 */

private void rightRotate(RBNode<T> y){

    //1. 将y的左子节点赋给x的右子节点,并将x赋给y左子节点的父节点(y左子节点非空时)

    RBNode<T> x = y.left;

    y.left = x.right;

    if(x.right != null){

        x.right.parent = y;

    }

     

    //2. 将x的父节点p(非空时)赋给y的父节点,同时更新p的子节点为y(左或右)

    x.parent = y.parent;

    if(y.parent == null){

        this.root = x;//如果y的父节点为空(即y为根节点),则旋转后将x设为根节点

    }else{

        if(y == y.parent.left){//如果y是左子节点

            y.parent.left = x;//则将x也设置为左子节点

        }else{

            y.parent.right = x;//否则将x设置为右子节点

        }

    }

    //3. 将x的左子节点设为y,将y的父节点设为y

    x.right = y;

    y.parent = x;

}

关于红黑树的左旋右旋

关于红黑树的左旋右旋







传说java爆点




以上是关于关于红黑树的左旋右旋的主要内容,如果未能解决你的问题,请参考以下文章

红黑树(Red-Black Tree)图文解析

红黑树(Red-Black Tree)图文解析

001 红黑树之 原理和算法详细介绍

红黑树理解右旋

教你轻松理解红黑树的实现及原理

红黑树的代码实现