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的父节点,且X是Y的左孩子,Y原来的左孩子成为X的右孩子,填补Y的空缺。如果是X右旋的话,就是把X的左孩子Y作为X的父节点,且X是Y的右孩子,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取代node在parent子节点的位置,否则node原来就是根结点,将right设置为根结点*/ if (parent) { if (node == parent->rb_left) parent->rb_left = right; else parent->rb_right = right; } else root->rb_node = right;
/*设置right为node的双亲结点*/ 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取代node在parent子节点的位置,否则node原来就是根结点,将left设置为根结点*/ if (parent) { if (node == parent->rb_right) parent->rb_right = left; else parent->rb_left = left; } else root->rb_node = left; /*设置left为node的双亲结点*/ rb_set_parent(node, left); }
|
rb_insert_color()
什么时候用左旋,什么时候用右旋?
当有不满足红黑树特性的情况出现,且无法通过涂改颜色之类的操作来满足(叔、父节点颜色不同,具体的话就是叔节点是黑的,父节点是红的,必然是这样的)。那么祖父节点(必然是黑节点)就需要旋转。右边比左边多,就需要右转,左边比右边多就需要左旋。
下图所示,G的右路黑路径(2)比左路(1)高,G需要右旋。如果G要进行右旋,但是导致失衡的N、P跟G不在同一直线上。(不在一条直线上,旋转会带走插入的红点N,下一步变颜色的时候会导致新一轮的失衡),所以先要搞成一条直线,N是P的右节点,所以P要先来一个左旋,如下图一。
图(一)
图一中已经左旋完毕了,这时候要进行G的右旋,先交换N、P指针。但是由于N、P都是红色,且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, parent为node的双亲结点*/ 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; } /*如果父节点是红色的,但是叔节点是黑色的,插入的节点是父节点的右孩子,父节点又是祖父节点的左孩子。那么就父节点进行左旋操作并且切换当前的节点和父节点(目的是将N、P、G变为一条直线上),如上图一左变成图二左部分*/ if (parent->rb_right == node) { register struct rb_node *tmp; __rb_rotate_left(parent, root); tmp = parent; parent = node; node = tmp; } /*此时,父节点是红色的,但是叔节点是黑色,节点是父节点的左节点,父节点是祖父节点的左节点,那么祖父节点进行右旋操作。如图二所示,P是N和G的父节点,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; }
/*如果父节点是红色的,但是叔节点是黑色的,插入的节点是父节点的左孩子,父节点又是祖父节点的右孩子。那么就父节点进行右旋操作并且切换当前的节点和父节点(目的是将N、P、G变为一条直线上)*/ 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的颜色为黑便会违背红黑树的特性,因此需要进行调节,传入的参数为child、parent,即待删节点中序遍历直接后驱节点的子节点和父节点,因为这个时候改删的节点已经删掉了!
第一种情况:删除的结点为根结点,而它的一个红色孩子成为了根,这里只需要将结点改成黑色即可;
第二种情况:如上图左所示,删除了B结点右子树上的一个黑结点后,被删除结点的子结点为红色,BD红色相连,并且B左子树黑高度比右子树高1,此时只需要将D染成黑色即可,即上图右;
针对于这两种情况的判断就是在while的条件中,如果属于这两种情况,并且node不为空就执行rb_set_black(node);
第三种情况,删除黑色结点后,导致包含闪出结点的所有路径上的黑高度少1,即删除节点以及child都为黑的情况,此时又跟child的兄弟节点相关了,函数中child用node表示,下面也都改为node,又分为如下几种情况;
case 1:node的兄弟other是红色,这种情况下,other的左右子结点都是黑色的,如下图左所示。此时只需要将A、C颜色互相,并且parent进行左旋操作,此时node结点B又获得了新的兄弟结点D,如下图右所示。但是此时B子树的黑高度仍然比D和E少1,但是这进入了一个新的case(见下case 2和case 3),即兄弟结点uncle为黑的情况‘
case 2:node的兄弟other是黑色,且other的左右孩子都是黑色;如下图左所示;此时的操作很简单,将C变为红色,然后将node指向A,然后重新获取A的双亲结点为parent,即下图右所示。由于删除了一个黑节点,所以B子树的黑高度会比C的黑高度少1,这里将C设置为红色就是为了给C子树的黑高度减1,但是在这里会让整个以A为根的子树黑高度减1,不过没关系,跳出循环之后将A设置为黑色,这样就会使之满足红黑树性质。当然这个A不一定是红色,如果是黑色,也就是下一次循环的时候node还是黑色,那就进入循环,继续根据node的具体情况进行判断,这是一个迭代的过程,最终的情况就是迭代到其它的情况,因为即使运气很差也会最终向上迭代到树根。
case 3:node的兄弟other是黑色,且other的左孩子是红色,右孩子为黑色;如下图左所示,
此时先将C和D的颜色互换,然后C结点右旋,结果如下图右所示。通过图中的操作其实是将case3转换成case4,此时A右子树黑深度仍然比左子树的深度高1。
case 4:node的兄弟other是黑色,且other的右孩子是红色,如下图左所示;此时将C的颜色设置成A的颜色,然后将A以及E设置成黑色,然后A进行左旋,结果如下图右所示。如果A刚开始就是黑色,无非就是右图中C节点为黑色,还是满足性质。对下图左这样处理的原因有两个:(1)要增加B子树的黑高度;(2)要保持A右子树的黑高度不变。因此,如果parent本身就是黑色,那么实际只需要parent进行左旋,将E改为黑色即可;如果parent为红色,为了给B子树增加黑高度,parent需要左旋和变黑,为了不让整个子树黑高度增加,就需要将C变红,然后E又需要变黑。所以将C改为A的颜色最为方便。
/*删除的结点为黑色时,需要对红黑树进行进一步调整,在node与parent之前,刚刚删除了一个黑色节点。现在树很可能不平衡, node与parent也可能红色冲突。本函数进行树的性质的修正,以使树恢复平衡。在一些情况下问题会转移到上一层节点,则须对上一层节点进行递归检查与修正。本函数中的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) { /*当node为parent左叶子结点的情况*/ 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,注意此时node的parent地址还是原来的*/ 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,直接建立其child与parent的连接*/ 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; } |