红黑树详解(源码+图示)

Rbtree.h文件中数据结构及函数

rb_node

红黑树节点数据结构中使用成员rb_parent_color同时存储两种数据,一是其双亲结点的地址,另一是此结点的着色。__attribute__((aligned(sizeof(long))))属性保证了红黑树中的每个结点的首地址都是32位对齐的(在32位机上),也就是说每个结点首地址的bit[1]bit[0]都是0,因此就可以使用bit[0]来存储结点的颜色属性而不干扰到其双亲结点首地址的存储。

struct rb_node

{

 /*30位存储双亲节点地址,最后一位为此节点颜色,低两位默认为0,表示为红色,若最后一位为1则表示为黑色*/

    unsigned long  rb_parent_color;  

#define RB_RED 0

#define RB_BLACK 1

struct rb_node *rb_right;     /*右子节点*/

struct rb_node *rb_left;      /*左子结点*/

} __attribute__((aligned(sizeof(long))));    

rb_root

/*红黑树的根节点*/

struct rb_root

{

struct rb_node *rb_node;

};

rb_parent_color操作函数

/*获取双亲节点的地址和此节点颜色,& ~3表示将倒数两位位清0,其余位保持不变*/

#define rb_parent(r)   ((struct rb_node *)((r)->rb_parent_color & ~3))

/*获取此节点的颜色,最低位表示颜色,1表示黑色,0表示红色*/

#define rb_color(r)   ((r)->rb_parent_color & 1)

/*判断此节点是否为红色*/

#define rb_is_red(r)   (!rb_color(r))

/*判断此节点是否为黑色*/

#define rb_is_black(r) rb_color(r)

/*将此节点设置为红色,&~1表示将最后一位清0,其余位不变*/

#define rb_set_red(r)  do { (r)->rb_parent_color &= ~1; } while (0)

/*将此节点设置为黑色*/

#define rb_set_black(r)  do { (r)->rb_parent_color |= 1; } while (0)

rb_set_parent()

/*设置双亲节点地址的函数,首先&3保持低两位不变,将高30位清0,然后将P设置为双亲地址*/

static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)

{

rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;

}

rb_set_color()

/*设置结点颜色属性的函数,先&~1将最低位清0,再获取color的颜色属性*/

static inline void rb_set_color(struct rb_node *rb, int color)

{

rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;

}

 

/*初始化指向红黑树根结点的指针*/

#define RB_ROOT (struct rb_root) { NULL, }

/*用来获得包含struct rb_node的结构体的首地址 */

#define rb_entry(ptr, type, member) container_of(ptr, type, member)

/*判断树是否为空*/

#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)

/*判断节点的双亲节点是否为自身*/

#define RB_EMPTY_NODE(node) (rb_parent(node) == node)

/*设置节点的双亲节点为自身*/

#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))

rb_init_node()

/*初始化新节点*/

static inline void rb_init_node(struct rb_node *rb)

{

rb->rb_parent_color = 0;

rb->rb_right = NULL;

rb->rb_left = NULL;

RB_CLEAR_NODE(rb);

}

rb_link_node()

/*将节点作为子节点连入红黑树*/

static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,

struct rb_node ** rb_link)

{

/*设置其双亲结点的首地址(根结点的双亲结点为NULL),此结点颜色默认为红色*/

    node->rb_parent_color = (unsigned long )parent;

node->rb_left = node->rb_right = NULL;

/*rb_link一般在调用前,就说明了是parent的左叶还是右叶 */

*rb_link = node;

}

Rbtree.c文件中函数

当在红黑树上进行插入和删除操作时,对树做了修改,结果可能会违反红黑树的那五条性质。为了保持这些性质,就要改变树中某些结点的颜色和指针结构。

    指针结构的修改时通过旋转来完成的,这是一种能保持二叉查找树性质的查找树局部操作:即左旋(右子为轴,当前结点左旋)和右旋(左子为轴,当前结点右旋:

 

左旋:比如说,需要把x旋转为y的左结点。整个算法的思路非常清晰:从上至下,先得到y指针,将x的右指针指向y的左结点,然后利用parent函数得到x的父亲结点,如果为NULL,则y为新的根,如果不为NULL,则根据x是其父亲的左孩子还是右孩子,将指针指向y。最后将y的左指针指向x,完成旋转。值得注意的是,算法是具有顺序的逻辑步骤,不能够调换顺序,如果改变赋值的顺序会造成内存失去指针指向,出现内存错误。

个人理解:假如X左旋,就是把X的右孩子Y作为X的父节点,且XY的左孩子,Y原来的左孩子成为X的右孩子,填补Y的空缺。如果是X右旋的话,就是把X的左孩子Y作为X的父节点,且XY的右孩子,Y原来的右孩子成为X的左孩子。更简洁明了一点左旋就是交换右子树和父节点,右旋就是交换左子树和父节点。

__rb_rotate_left()

/*结点左旋操作,右子为轴,当前结点左旋,node为进行左旋操作的结点,旋转前后对比上图*/

static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)

{

/*先获得待左旋结点node的右子结点right和双亲节点parent*/

    struct rb_node *right = node->rb_right; 

struct rb_node *parent = rb_parent(node);

    

    /*right的左子节点转为node的右子结点*/

if ((node->rb_right = right->rb_left))

rb_set_parent(right->rb_left, node);

    /*node作为right的左子结点*/

    right->rb_left = node;

 

    /*node的双亲节点parent修改为right的双亲节点*/

rb_set_parent(right, parent);

 

    /*如果双亲结点不为空,表示node不是根结点,用right取代nodeparent子节点的位置,否则node原来就是根结点,将right设置为根结点*/

if (parent)

{

if (node == parent->rb_left)

parent->rb_left = right;

else

parent->rb_right = right;

}

else

root->rb_node = right;

 

    /*设置rightnode的双亲结点*/

rb_set_parent(node, right);

}

__rb_rotate_right()

/*结点右旋操作,左子为轴,当前结点右旋,node为进行右旋操作的结点,旋转前后对比上图*/

static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)

{

/*先获得待左旋结点node的左子结点left和双亲节点parent*/

    struct rb_node *left = node->rb_left;

struct rb_node *parent = rb_parent(node);

 

    /*left的右子节点转为node的左子结点*/

if ((node->rb_left = left->rb_right))

rb_set_parent(left->rb_right, node);

 

*node作为left的右子结点*/

    left->rb_right = node;

 

    /*node的双亲节点parent修改为right的双亲节点*/

rb_set_parent(left, parent);

 

    /*如果双亲结点不为空,表示node不是根结点,用left取代nodeparent子节点的位置,否则node原来就是根结点,将left设置为根结点*/

if (parent)

{

if (node == parent->rb_right)

parent->rb_right = left;

else

parent->rb_left = left;

}

else

root->rb_node = left;

    /*设置leftnode的双亲结点*/

       rb_set_parent(node, left);

}

 

rb_insert_color()

什么时候用左旋,什么时候用右旋?

    当有不满足红黑树特性的情况出现,且无法通过涂改颜色之类的操作来满足(叔、父节点颜色不同,具体的话就是叔节点是黑的,父节点是红的,必然是这样的)。那么祖父节点(必然是黑节点)就需要旋转。右边比左边多,就需要右转,左边比右边多就需要左旋。

    下图所示,G的右路黑路径(2)比左路(1)高,G需要右旋。如果G要进行右旋,但是导致失衡的NPG不在同一直线上。(不在一条直线上,旋转会带走插入的红点N,下一步变颜色的时候会导致新一轮的失衡),所以先要搞成一条直线,NP的右节点,所以P要先来一个左旋,如下图一。

 

()

图一中已经左旋完毕了,这时候要进行G的右旋,先交换NP指针。但是由于NP都是红色,且P是要被拉上去的,G是要被拉下来的,所以可以先把P设置成黑色,G设置成红色,再进行右旋。如图()

 

()

/*;该函数与rb_link_node()配套使用,rb_link_node()为结点插入函数,首先像二叉查找树一样插入一个新结点,然后rb_insert_color()函数根据情况作出相应的调整,以使其满足红黑树的颜色属性*/

void rb_insert_color(struct rb_node *node, struct rb_root *root)

{

struct rb_node *parent, *gparent;

 

/*如果插入的是根结点,直接修改其颜色属性为黑色,rb_link_node将结点插入时颜色属性默认为红色;

 如果插入结点的父结点为黑色,那么插入后红黑树颜色特性依旧是有效的,因为插入的结点默认为红色,不会改变null上经过的黑色结点数目,也不会违背连续两个红色结点特性,所以不需要做任何修改;

 否则需要判断调整,使用while循环,判断双亲结点是否存在以及颜色属性是否为红色*/

while ((parent = rb_parent(node)) && rb_is_red(parent))

{

    /*获取node的祖父节点 gparent, parentnode的双亲结点*/

        gparent = rb_parent(parent);

 

if (parent == gparent->rb_left)

{

/*获取node的叔结点*/

            register struct rb_node *uncle = gparent->rb_right;

 

    /*如果node的双亲结点和叔结点都为红色,那么他们都将变成黑色,祖父节点将变成红色(这是为了满足一个结点到Null路径上所有黑结点数目一致),但是如果这祖父节点变成root节点了,又要满足root结点要是黑色,所以这个祖父节点还需要进行递归的判断*/

if (uncle && rb_is_red(uncle))

{

rb_set_black(uncle);

rb_set_black(parent);

rb_set_red(gparent);

node = gparent;

continue;

}

    /*如果父节点是红色的,但是叔节点是黑色的,插入的节点是父节点的右孩子,父节点又是祖父节点的左孩子。那么就父节点进行左旋操作并且切换当前的节点和父节点(目的是将NPG变为一条直线上),如上图一左变成图二左部分*/

if (parent->rb_right == node)

{

register struct rb_node *tmp;

__rb_rotate_left(parent, root);

tmp = parent;

parent = node;

node = tmp;

}

    /*此时,父节点是红色的,但是叔节点是黑色,节点是父节点的左节点,父节点是祖父节点的左节点,那么祖父节点进行右旋操作。如图二所示,PNG的父节点,G已知是黑色的,这时候不满足红节点的叶子节为i黑色,所以要将祖父节点颜色涂红,父节点颜色涂黑*/

rb_set_black(parent);

rb_set_red(gparent);

__rb_rotate_right(gparent, root);

}

        else    //即父结点为祖父结点的右子结点

        {

register struct rb_node *uncle = gparent->rb_left;

     

    /*如果node的双亲结点和叔结点都为红色,那么他们都将变成黑色,祖父节点将变成红色(这是为了满足一个结点到Null路径上所有黑结点数目一致),但是如果这祖父节点变成root节点了,又要满足root结点要是黑色,所以这个祖父节点还需要进行递归的判断*/

if (uncle && rb_is_red(uncle))

{

rb_set_black(uncle);

rb_set_black(parent);

rb_set_red(gparent);

node = gparent;

continue;

}

 

    /*如果父节点是红色的,但是叔节点是黑色的,插入的节点是父节点的左孩子,父节点又是祖父节点的右孩子。那么就父节点进行右旋操作并且切换当前的节点和父节点(目的是将NPG变为一条直线上)*/

if (parent->rb_left == node)

{

register struct rb_node *tmp;

__rb_rotate_right(parent, root);

tmp = parent;

parent = node;

node = tmp;

}

    /*此时,父节点是红色的,但是叔节点是黑色,节点是父节点的右子节点,父节点是祖父节点的右子节点,那么祖父节点进行左旋操作。这时候不满足红节点的叶子节为i黑色,所以要将祖父节点颜色涂红,父节点颜色涂黑*/

rb_set_black(parent);

rb_set_red(gparent);

__rb_rotate_left(gparent, root);

}

}

 

    /*将根结点设置为黑色*/

rb_set_black(root->rb_node);

}

__rb_erase_color()

在删除过程中,如果遇到node的颜色为黑便会违背红黑树的特性,因此需要进行调节,传入的参数为childparent,即待删节点中序遍历直接后驱节点的子节点和父节点,因为这个时候改删的节点已经删掉了!

     

  

第一种情况:删除的结点为根结点,而它的一个红色孩子成为了根,这里只需要将结点改成黑色即可;

第二种情况:如上图左所示,删除了B结点右子树上的一个黑结点后,被删除结点的子结点为红色,BD红色相连,并且B左子树黑高度比右子树高1,此时只需要将D染成黑色即可,即上图右;

针对于这两种情况的判断就是在while的条件中,如果属于这两种情况,并且node不为空就执行rb_set_black(node)

第三种情况,删除黑色结点后,导致包含闪出结点的所有路径上的黑高度少1,即删除节点以及child都为黑的情况,此时又跟child的兄弟节点相关了,函数中childnode表示,下面也都改为node,又分为如下几种情况;

case 1node的兄弟other是红色,这种情况下,other的左右子结点都是黑色的,如下图左所示。此时只需要将AC颜色互相,并且parent进行左旋操作,此时node结点B又获得了新的兄弟结点D,如下图右所示。但是此时B子树的黑高度仍然比DE1,但是这进入了一个新的case(见下case 2case 3),即兄弟结点uncle为黑的情况‘

  

  case 2node的兄弟other是黑色,且other的左右孩子都是黑色;如下图左所示;此时的操作很简单,将C变为红色,然后将node指向A,然后重新获取A的双亲结点为parent,即下图右所示。由于删除了一个黑节点,所以B子树的黑高度会比C的黑高度少1,这里将C设置为红色就是为了给C子树的黑高度减1,但是在这里会让整个以A为根的子树黑高度减1,不过没关系,跳出循环之后将A设置为黑色,这样就会使之满足红黑树性质。当然这个A不一定是红色,如果是黑色,也就是下一次循环的时候node还是黑色,那就进入循环,继续根据node的具体情况进行判断,这是一个迭代的过程,最终的情况就是迭代到其它的情况,因为即使运气很差也会最终向上迭代到树根。

 

 

case 3node的兄弟other是黑色,且other的左孩子是红色,右孩子为黑色;如下图左所示,

此时先将CD的颜色互换,然后C结点右旋,结果如下图右所示。通过图中的操作其实是将case3转换成case4,此时A右子树黑深度仍然比左子树的深度高1

 

 

case 4node的兄弟other是黑色,且other的右孩子是红色,如下图左所示;此时将C的颜色设置成A的颜色,然后将A以及E设置成黑色,然后A进行左旋,结果如下图右所示。如果A刚开始就是黑色,无非就是右图中C节点为黑色,还是满足性质。对下图左这样处理的原因有两个:(1)要增加B子树的黑高度;(2)要保持A右子树的黑高度不变。因此,如果parent本身就是黑色,那么实际只需要parent进行左旋,将E改为黑色即可;如果parent为红色,为了给B子树增加黑高度,parent需要左旋和变黑,为了不让整个子树黑高度增加,就需要将C变红,然后E又需要变黑。所以将C改为A的颜色最为方便。

  

 

/*删除的结点为黑色时,需要对红黑树进行进一步调整,在nodeparent之前,刚刚删除了一个黑色节点。现在树很可能不平衡, nodeparent也可能红色冲突。本函数进行树的性质的修正,以使树恢复平衡。在一些情况下问题会转移到上一层节点,则须对上一层节点进行递归检查与修正。本函数中的while循环实际上实现了这种递归。*/

static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,

     struct rb_root *root)

{

/* other用来保存兄弟节点,这是树的修正过程中一个重要的参考节点*/

    struct rb_node *other;

 

    /*循环条件:node不是红节点且node不是根节点。  

    解释:对于红节点或根节点,直接涂黑即可解决问题*/

while ((!node || rb_is_black(node)) && node != root->rb_node)

{

/*nodeparent左叶子结点的情况*/

        if (parent->rb_left == node)

{

/*获得兄弟结点*/

            other = parent->rb_right;

if (rb_is_red(other))

{

/*对应case 1的情况,解释见上*/

                rb_set_black(other);

rb_set_red(parent);

__rb_rotate_left(parent, root);

other = parent->rb_right;

}

if ((!other->rb_left || rb_is_black(other->rb_left)) &&

    (!other->rb_right || rb_is_black(other->rb_right)))

{

/*对应case 2的情况,解释见上*/

                rb_set_red(other);

node = parent;

parent = rb_parent(node);

}

else

{

if (!other->rb_right || rb_is_black(other->rb_right))

{

                    /*对应case 3的情况,解释见上*/

rb_set_black(other->rb_left);

rb_set_red(other);

__rb_rotate_right(other, root);

other = parent->rb_right;

}

                /*对应case 4的情况,解释见上*/

rb_set_color(other, rb_color(parent));

rb_set_black(parent);

rb_set_black(other->rb_right);

__rb_rotate_left(parent, root);

node = root->rb_node;

break;

}

}

else

{

other = parent->rb_left;

if (rb_is_red(other))

{

rb_set_black(other);

rb_set_red(parent);

__rb_rotate_right(parent, root);

other = parent->rb_left;

}

if ((!other->rb_left || rb_is_black(other->rb_left)) &&

    (!other->rb_right || rb_is_black(other->rb_right)))

{

rb_set_red(other);

node = parent;

parent = rb_parent(node);

}

else

{

if (!other->rb_left || rb_is_black(other->rb_left))

{

rb_set_black(other->rb_right);

rb_set_red(other);

__rb_rotate_left(other, root);

other = parent->rb_left;

}

rb_set_color(other, rb_color(parent));

rb_set_black(parent);

rb_set_black(other->rb_left);

__rb_rotate_right(parent, root);

node = root->rb_node;

break;

}

}

}

if (node)

rb_set_black(node);

}

rb_erase()

像二叉查找树的删除操作一样,首先需要找到所需删除的结点,然后根据该结点左右子树的有无分为三种情形:

 

node结点的颜色属性为黑色,则需要调用__rb_erase_color函数来进行调整。

结合红黑树的定义分析,如果删除红色节点会带来什么影响:

a:树中的黑节点高度仍保持不变

b:不存在两个相邻的红节点

c:如果删除的是红色节点,那么该节点肯定不是根节点

剩下的两条肯定满足,这样看来如果删除了红色节点对红黑树并没有任何影响。

 

那么,如果删除了黑色节点呢:

a:如果node是根节点,而它的一个红色孩子成为了根,违反(2

b:如果删除node后,node的父节点与其新的子节点同为红色,违反(4

c:删除node后将导致包含node的所有路径上的黑高度少1,违反(5

其它满足。

从上面的分析可以看出来删除了黑节点才会真正影响红黑树的性质。

/*红黑树结点删除函数*/

void rb_erase(struct rb_node *node, struct rb_root *root)

{

struct rb_node *child, *parent;

int color;

    

/*寻找删除node后与parent相连的child

  如果node无左子结点,那么child便为其右子结点;

  如果node无右子结点,那么child便为其左子结点;

  如果node同时有左右子结点,用node右子结点的最左子树结点来取代node*/

if (!node->rb_left)

child = node->rb_right;

else if (!node->rb_right)

child = node->rb_left;

else

{

/*old指向待删除的结点*/

        struct rb_node *old = node, *left;

        

        /*node指向将要取代old位置的结点,即old右子结点的最左子树结点(old的中序遍历直接后驱节点)*/

node = node->rb_right;

while ((left = node->rb_left) != NULL)

node = left;

 

        /*将新node加到old双亲结点对应子结点,取代old,注意此时nodeparent地址还是原来的*/

if (rb_parent(old)) 

        {

if (rb_parent(old)->rb_left == old)

rb_parent(old)->rb_left = node;

else

rb_parent(old)->rb_right = node;

}

        else

root->rb_node = node;

        

        /*node的右子树改为其原parent的左子树*/

child = node->rb_right;

parent = rb_parent(node);

color = rb_color(node);

 

if (parent == old) {

parent = node;

} else {

if (child)

rb_set_parent(child, parent);

parent->rb_left = child;

        /*old的右子树改为node的右子树*/

node->rb_right = old->rb_right;

rb_set_parent(old->rb_right, node);

}

    /*此时才修改node的双亲地址,注意的是,此时node的颜色也变成了和old一致,那么node原来层次以上的结构都不会有问题,只有在node原来颜色为黑色时,node及以下子树经过调整才会违背红黑树的特性,所以上面才会color = rb_color(node);并在后面判断color属性*/

node->rb_parent_color = old->rb_parent_color;

        /*old的左子树改为node的左子树*

node->rb_left = old->rb_left;

rb_set_parent(old->rb_left, node);

 

goto color;

    /*在存在左右子树的情况中,从删除前后红黑树结构变化来看,最终实际是删除了node,只是将其挪到了old位置,然后将其颜色也改为node的颜色……*/

}

    /*对于缺少左子树或者右子树的node,直接建立其childparent的连接*/

parent = rb_parent(node);

color = rb_color(node);

 

if (child)

rb_set_parent(child, parent);

if (parent)

{

if (parent->rb_left == node)

parent->rb_left = child;

else

parent->rb_right = child;

}

else

root->rb_node = child;

    /*如果删除结点的颜色属性为黑色,则需调用__rb_erase_color函数来进行调整*/

 color:

if (color == RB_BLACK)

__rb_erase_color(child, parent, root);

}

rb_first()

/*返回红黑树中最左结点,即排序最小的结点 */

struct rb_node *rb_first(const struct rb_root *root)

{

struct rb_node *n;

 

n = root->rb_node;

if (!n)

return NULL;

while (n->rb_left)

n = n->rb_left;

return n;

}

rb_last()

/*返回红黑树中最右结点,即排序最大的结点 */

struct rb_node *rb_last(const struct rb_root *root)

{

struct rb_node *n;

 

n = root->rb_node;

if (!n)

return NULL;

while (n->rb_right)

n = n->rb_right;

return n;

}

rb_next()

/*node中序遍历的直接后驱结点,即排序在node后一个的结点*/

struct rb_node *rb_next(const struct rb_node *node)

{

struct rb_node *parent;

 

if (rb_parent(node) == node)

return NULL;

 

/*如果node有右分支,那么其右分支的最左节点即为所需结点*/

if (node->rb_right) {

node = node->rb_right; 

while (node->rb_left)

node=node->rb_left;

return (struct rb_node *)node;

}

/*node不存在右分支时,沿父节点向上遍历,找到第一个出现左分支的节点便是需要的节点*/

while ((parent = rb_parent(node)) && node == parent->rb_right)

node = parent;

 

return parent;

}

rb_prev()

/*node中序遍历的直接前驱结点,即排序在node前一个的结点*/

struct rb_node *rb_prev(const struct rb_node *node)

{

struct rb_node *parent;

 

if (rb_parent(node) == node)

return NULL;

 

if (node->rb_left) {

node = node->rb_left; 

while (node->rb_right)

node=node->rb_right;

return (struct rb_node *)node;

}

while ((parent = rb_parent(node)) && node == parent->rb_left)

node = parent;

 

return parent;

}

 

rb_replace_node()

/*new结点取代victim结点*/

void rb_replace_node(struct rb_node *victim, struct rb_node *new,

     struct rb_root *root)

{

struct rb_node *parent = rb_parent(victim);

 

if (parent) {

if (victim == parent->rb_left)

parent->rb_left = new;

else

parent->rb_right = new;

} else {

root->rb_node = new;

}

if (victim->rb_left)

rb_set_parent(victim->rb_left, new);

if (victim->rb_right)

rb_set_parent(victim->rb_right, new);

 

*new = *victim;

}

 

红黑树的应用Rblist

Rblist.h文件中数据结构及函数

rblist

struct rblist {

struct rb_root entries;    //liat的根结点

unsigned int  nr_entries;   //list中结点的数目

 

    /*比较函数,返回值=value(rbn) - value(entry)*/

int (*node_cmp)(struct rb_node *rbn, const void *entry);

 

    /*为新结点创建红黑树结点结构*/

struct rb_node *(*node_new)(struct rblist *rlist, const void *new_entry);

    

    /*释放红黑树中指定结点结构空间*/

void (*node_delete)(struct rblist *rblist, struct rb_node *rb_node);

};

rblist__empty()

/*判断树是否为空*/

static inline bool rblist__empty(const struct rblist *rblist)

{

return rblist->nr_entries == 0;

}

rblist__nr_entries()

/*获取树中结点的数目*/

static inline unsigned int rblist__nr_entries(const struct rblist *rblist)

{

return rblist->nr_entries;

}

Rblist.c文件中函数

rblist__add_node()

/*结点插入红黑树中适当位置*/

int rblist__add_node(struct rblist *rblist, const void *new_entry)

{

/*获取根结点*/

    struct rb_node **p = &rblist->entries.rb_node;

struct rb_node *parent = NULL, *new_node;

 

    /*根据new_entry的值找到合适的插入位置*/

while (*p != NULL) {

int rc;

parent = *p;

        /*比较,若parent大,则往左子树,若parent小则往右子树*/

rc = rblist->node_cmp(parent, new_entry);

if (rc > 0)

p = &(*p)->rb_left;

else if (rc < 0)

p = &(*p)->rb_right;

else

return -EEXIST;

}

    /*为新结点创建红黑树结点结构*/

new_node = rblist->node_new(rblist, new_entry);

if (new_node == NULL)

return -ENOMEM;

    /*将结点连入红黑树中,并为其着色*/

rb_link_node(new_node, parent, p);

rb_insert_color(new_node, &rblist->entries);

/*红黑树结点数目+1*/

    ++rblist->nr_entries;

 

return 0;

}

 

rblist__remove_node()

/*删除结点,并释放其空间(为何rblist->nr_entries没有执行减一操作?)*/

void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)

{

rb_erase(rb_node, &rblist->entries);

rblist->node_delete(rblist, rb_node);

}

rblist__find()

/*红黑树中查找指定结点*/

struct rb_node *rblist__find(struct rblist *rblist, const void *entry)

{

struct rb_node **p = &rblist->entries.rb_node;

struct rb_node *parent = NULL;

 

while (*p != NULL) {

int rc;

parent = *p;

rc = rblist->node_cmp(parent, entry);

if (rc > 0)

p = &(*p)->rb_left;

else if (rc < 0)

p = &(*p)->rb_right;

else

return parent;

}

return NULL;

}

rblist__init()

/*红黑树结构初始化*/

void rblist__init(struct rblist *rblist)

{

if (rblist != NULL) {

rblist->entries  = RB_ROOT;

rblist->nr_entries = 0;

}

return;

}

rblist__delete()

/*按照中序遍历的方式删除红黑树中所有结点,并释放其空间*/

void rblist__delete(struct rblist *rblist)

{

if (rblist != NULL) {

struct rb_node *pos, *next = rb_first(&rblist->entries);

 

while (next) {

pos = next;

next = rb_next(pos);

rb_erase(pos, &rblist->entries);

rblist->node_delete(rblist, pos);

}

free(rblist);

}

}

rblist__entry()

/*查找红黑树中从小到大排序的第idx个结点,即中序遍历的第idx个结点*/

struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx)

{

struct rb_node *node;

 

for (node = rb_first(&rblist->entries); node; node = rb_next(node)) {

if (!idx--)

return node;

}

return NULL;

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章