转自:https://www.cnblogs.com/hellokitty2/p/15362596.html

另外可参考:https://zhuanlan.zhihu.com/p/26599934

一、学习笔记

1. rbtree 简介

rbtree,全称是 Red-Black Tree,又称为“红黑树”,它一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。

红黑树的特性:
(1) 每个节点或者是黑色,或者是红色。
(2) 根节点是黑色。
(3) 每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL 或 NULL)的叶子节点!]
(4) 如果一个节点是红色的,则它的子节点必须是黑色的。
(5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。此特性确保没有一条路径会比其他路径长出两倍,因而,红黑树是相对是接近平衡的二叉树。

对红黑树的所有操作都要保持红黑树的特性不变,红黑树的应用比较广泛,主要是用它来存储有序的数据,它的时间复杂度是O(lgn),效率非常之高。cfs_rq就是使用红黑树存储任务的。

2. 红黑树的基本操作

(1) 左旋

左旋示例图(以x为节点进行左旋):

                               z
x /
/ \ --(左旋)--> x
y z /
y

对 x 进行左旋,意味着,将 “x的右孩子” 设为 “x的父亲节点”,即,将x变成了一个左节点(x成了为z的左孩子)。 因此,左旋中的 “左”,意味着 “被旋转的节点将变成一个左节点”。

(2) 右旋

右旋示例图(以x为节点进行右旋):

                               y
x \
/ \ --(右旋)--> x
y z \
z

对 x 进行右旋,意味着,将 “x的左孩子” 设为 “x的父亲节点”,即,将x变成了一个右节点(x成了为y的右孩子),因此,右旋中的 “右”,意味着 “被旋转的节点将变成一个右节点”。

(3) 添加

将一个节点插入到红黑树中,首先,将红黑树当作一颗二叉查找树,将节点插入;然后,将节点着色为红色;最后,通过旋转和重新着色等方法来修正该树,使之重新成为一颗红黑树。

(4) 删除

将红黑树内的某一个节点删除。需要执行的操作依次是:首先,将红黑树当作一颗二叉查找树,将该节点从二叉查找树中删除;然后,通过"旋转和重新着色"等一系列来修正该树,使之重新成为一棵红黑树。

二、移植测试

1. 移植 linux/include/linux/rbtree.h

/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
linux/include/linux/rbtree.h
*/ #ifndef _LINUX_RBTREE_H
#define _LINUX_RBTREE_H //#include <linux/kernel.h>
//#include <linux/stddef.h>
//#include <linux/rcupdate.h> /*------------------------- I add -------------------------*/
#include <stdlib.h> #define NULL ((void *)0) #define RB_RED 0
#define RB_BLACK 1 #define WRITE_ONCE(p, v) (p)=(v) #define unlikely(x) x #define rcu_assign_pointer(p, v) (p)=(v) typedef enum _bool {
false = 0,
true = 1,
} bool; #define __rb_parent(pc) ((struct rb_node *)(pc & ~3)) #define __rb_color(pc) ((pc) & 1)
#define __rb_is_black(pc) __rb_color(pc)
#define __rb_is_red(pc) (!__rb_color(pc))
#define rb_color(rb) __rb_color((rb)->__rb_parent_color)
#define rb_is_red(rb) __rb_is_red((rb)->__rb_parent_color)
#define rb_is_black(rb) __rb_is_black((rb)->__rb_parent_color) #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );}) /*------------------ end ----------------------------*/ struct rb_node {
unsigned long __rb_parent_color;
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
/* The alignment might seem pointless, but allegedly CRIS needs it */ struct rb_root {
struct rb_node *rb_node;
}; #define rb_parent(r) ((struct rb_node *)((r)->__rb_parent_color & ~3)) #define RB_ROOT (struct rb_root) { NULL, }
#define rb_entry(ptr, type, member) container_of(ptr, type, member) #define RB_EMPTY_ROOT(root) (READ_ONCE((root)->rb_node) == NULL) /* 'empty' nodes are nodes that are known not to be inserted in an rbtree */
#define RB_EMPTY_NODE(node) ((node)->__rb_parent_color == (unsigned long)(node))
#define RB_CLEAR_NODE(node) ((node)->__rb_parent_color = (unsigned long)(node)) extern void rb_insert_color(struct rb_node *, struct rb_root *);
extern void rb_erase(struct rb_node *, struct rb_root *); /* Find logical next and previous nodes in a tree */
extern struct rb_node *rb_next(const struct rb_node *);
extern struct rb_node *rb_prev(const struct rb_node *);
extern struct rb_node *rb_first(const struct rb_root *);
extern struct rb_node *rb_last(const struct rb_root *); /* Postorder iteration - always visit the parent after its children */
extern struct rb_node *rb_first_postorder(const struct rb_root *);
extern struct rb_node *rb_next_postorder(const struct rb_node *); /* Fast replacement of a single node without remove/rebalance/add/rebalance */
extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root);
extern void rb_replace_node_rcu(struct rb_node *victim, struct rb_node *new, struct rb_root *root); /*
* 传参(&node->rb, parent, new) node是用户数据结构中的rb_node成员,rb_link是在红黑树上遍历出来的位置,要么为
* parent的rb_left,要么为rb_right
*/
static inline void rb_link_node(struct rb_node *node, struct rb_node *parent, struct rb_node **rb_link)
{
node->__rb_parent_color = (unsigned long)parent;
node->rb_left = node->rb_right = NULL; *rb_link = node;
} static inline void rb_link_node_rcu(struct rb_node *node, struct rb_node *parent, struct rb_node **rb_link)
{
node->__rb_parent_color = (unsigned long)parent;
node->rb_left = node->rb_right = NULL; rcu_assign_pointer(*rb_link, node);
} #define rb_entry_safe(ptr, type, member) \
({ typeof(ptr) ____ptr = (ptr); \
____ptr ? rb_entry(____ptr, type, member) : NULL; \
}) /**
* rbtree_postorder_for_each_entry_safe - iterate in post-order over rb_root of
* given type allowing the backing memory of @pos to be invalidated
*
* @pos: the 'type *' to use as a loop cursor.
* @n: another 'type *' to use as temporary storage
* @root: 'rb_root *' of the rbtree.
* @field: the name of the rb_node field within 'type'.
*
* rbtree_postorder_for_each_entry_safe() provides a similar guarantee as
* list_for_each_entry_safe() and allows the iteration to continue independent
* of changes to @pos by the body of the loop.
*
* Note, however, that it cannot handle other modifications that re-order the
* rbtree it is iterating over. This includes calling rb_erase() on @pos, as
* rb_erase() may rebalance the tree, causing us to miss some nodes.
*/
#define rbtree_postorder_for_each_entry_safe(pos, n, root, field) \
for (pos = rb_entry_safe(rb_first_postorder(root), typeof(*pos), field); \
pos && ({ n = rb_entry_safe(rb_next_postorder(&pos->field), \
typeof(*pos), field); 1; }); \
pos = n) /*
* Leftmost-cached rbtrees.
*
* We do not cache the rightmost node based on footprint
* size vs number of potential users that could benefit
* from O(1) rb_last(). Just not worth it, users that want
* this feature can always implement the logic explicitly.
* Furthermore, users that want to cache both pointers may
* find it a bit asymmetric, but that's ok.
*/
struct rb_root_cached {
struct rb_root rb_root;
struct rb_node *rb_leftmost;
}; #define RB_ROOT_CACHED (struct rb_root_cached) { {NULL, }, NULL } /* Same as rb_first(), but O(1) */
#define rb_first_cached(root) (root)->rb_leftmost static inline void rb_insert_color_cached(struct rb_node *node, struct rb_root_cached *root, bool leftmost)
{
if (leftmost)
root->rb_leftmost = node;
rb_insert_color(node, &root->rb_root);
} static inline void rb_erase_cached(struct rb_node *node, struct rb_root_cached *root)
{
if (root->rb_leftmost == node)
root->rb_leftmost = rb_next(node);
rb_erase(node, &root->rb_root);
} static inline void rb_replace_node_cached(struct rb_node *victim, struct rb_node *new, struct rb_root_cached *root)
{
if (root->rb_leftmost == victim)
root->rb_leftmost = new;
rb_replace_node(victim, new, &root->rb_root);
} #endif /* _LINUX_RBTREE_H */

2. 移植 linux/lib/rbtree.c

/*
linux/lib/rbtree.c
*/ //#include <linux/rbtree_augmented.h>
//#include <linux/export.h> /*------------------------------------- I add ----------------------------------------------*/ #include "rbtree.h" //linux/rbtree.h struct rb_augment_callbacks {
void (*propagate)(struct rb_node *node, struct rb_node *stop);
void (*copy)(struct rb_node *old, struct rb_node *new);
void (*rotate)(struct rb_node *old, struct rb_node *new);
}; static inline void rb_set_parent_color(struct rb_node *rb, struct rb_node *p, int color)
{
rb->__rb_parent_color = (unsigned long)p | color;
} static inline void __rb_change_child(struct rb_node *old, struct rb_node *new, struct rb_node *parent, struct rb_root *root)
{
if (parent) {
if (parent->rb_left == old)
WRITE_ONCE(parent->rb_left, new);
else
WRITE_ONCE(parent->rb_right, new);
} else
WRITE_ONCE(root->rb_node, new);
} static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
{
rb->__rb_parent_color = rb_color(rb) | (unsigned long)p;
} static inline struct rb_node *__rb_erase_augmented(struct rb_node *node, struct rb_root *root, const struct rb_augment_callbacks *augment)
{
struct rb_node *child = node->rb_right;
struct rb_node *tmp = node->rb_left;
struct rb_node *parent, *rebalance;
unsigned long pc; if (!tmp) {
/*
* Case 1: node to erase has no more than 1 child (easy!)
*
* Note that if there is one child it must be red due to 5)
* and node must be black due to 4). We adjust colors locally
* so as to bypass __rb_erase_color() later on.
*/
pc = node->__rb_parent_color;
parent = __rb_parent(pc);
__rb_change_child(node, child, parent, root);
if (child) {
child->__rb_parent_color = pc;
rebalance = NULL;
} else
rebalance = __rb_is_black(pc) ? parent : NULL;
tmp = parent;
} else if (!child) {
/* Still case 1, but this time the child is node->rb_left */
tmp->__rb_parent_color = pc = node->__rb_parent_color;
parent = __rb_parent(pc);
__rb_change_child(node, tmp, parent, root);
rebalance = NULL;
tmp = parent;
} else {
struct rb_node *successor = child, *child2; tmp = child->rb_left;
if (!tmp) {
/*
* Case 2: node's successor is its right child
*
* (n) (s)
* / \ / \
* (x) (s) -> (x) (c)
* \
* (c)
*/
parent = successor;
child2 = successor->rb_right; augment->copy(node, successor);
} else {
/*
* Case 3: node's successor is leftmost under
* node's right child subtree
*
* (n) (s)
* / \ / \
* (x) (y) -> (x) (y)
* / /
* (p) (p)
* / /
* (s) (c)
* \
* (c)
*/
do {
parent = successor;
successor = tmp;
tmp = tmp->rb_left;
} while (tmp);
child2 = successor->rb_right;
WRITE_ONCE(parent->rb_left, child2);
WRITE_ONCE(successor->rb_right, child);
rb_set_parent(child, successor); augment->copy(node, successor);
augment->propagate(parent, successor);
} tmp = node->rb_left;
WRITE_ONCE(successor->rb_left, tmp);
rb_set_parent(tmp, successor); pc = node->__rb_parent_color;
tmp = __rb_parent(pc);
__rb_change_child(node, successor, tmp, root); if (child2) {
successor->__rb_parent_color = pc;
rb_set_parent_color(child2, parent, RB_BLACK);
rebalance = NULL;
} else {
unsigned long pc2 = successor->__rb_parent_color;
successor->__rb_parent_color = pc;
rebalance = __rb_is_black(pc2) ? parent : NULL;
}
tmp = successor;
} augment->propagate(tmp, NULL);
return rebalance;
} static inline void __rb_change_child_rcu(struct rb_node *old, struct rb_node *new, struct rb_node *parent, struct rb_root *root)
{
if (parent) {
if (parent->rb_left == old)
rcu_assign_pointer(parent->rb_left, new);
else
rcu_assign_pointer(parent->rb_right, new);
} else
rcu_assign_pointer(root->rb_node, new);
} /*--------------------------------------- end ------------------------------------------------*/ static inline void rb_set_black(struct rb_node *rb)
{
rb->__rb_parent_color |= RB_BLACK;
} static inline struct rb_node *rb_red_parent(struct rb_node *red)
{
return (struct rb_node *)red->__rb_parent_color;
} /*
* Helper function for rotations:
* - old's parent and color get assigned to new
* - old gets assigned new as a parent and 'color' as a color.
*/
static inline void __rb_rotate_set_parents(struct rb_node *old, struct rb_node *new, struct rb_root *root, int color)
{
struct rb_node *parent = rb_parent(old);
new->__rb_parent_color = old->__rb_parent_color;
rb_set_parent_color(old, new, color);
__rb_change_child(old, new, parent, root);
} static __always_inline void __rb_insert(struct rb_node *node, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
{
struct rb_node *parent = rb_red_parent(node), *gparent, *tmp; while (true) {
/*
* Loop invariant: node is red.
*/
if (unlikely(!parent)) {
/*
* The inserted node is root. Either this is the
* first node, or we recursed at Case 1 below and
* are no longer violating 4).
*/
rb_set_parent_color(node, NULL, RB_BLACK);
break;
} /*
* If there is a black parent, we are done.
* Otherwise, take some corrective action as,
* per 4), we don't want a red root or two
* consecutive red nodes.
*/
if(rb_is_black(parent))
break; gparent = rb_red_parent(parent); tmp = gparent->rb_right;
if (parent != tmp) { /* parent == gparent->rb_left */
if (tmp && rb_is_red(tmp)) {
/*
* Case 1 - node's uncle is red (color flips).
*
* G g
* / \ / \
* p u --> P U
* / /
* n n
*
* However, since g's parent might be red, and
* 4) does not allow this, we need to recurse
* at g.
*/
rb_set_parent_color(tmp, gparent, RB_BLACK);
rb_set_parent_color(parent, gparent, RB_BLACK);
node = gparent;
parent = rb_parent(node);
rb_set_parent_color(node, parent, RB_RED);
continue;
} tmp = parent->rb_right;
if (node == tmp) {
/*
* Case 2 - node's uncle is black and node is
* the parent's right child (left rotate at parent).
*
* G G
* / \ / \
* p U --> n U
* \ /
* n p
*
* This still leaves us in violation of 4), the
* continuation into Case 3 will fix that.
*/
tmp = node->rb_left;
WRITE_ONCE(parent->rb_right, tmp);
WRITE_ONCE(node->rb_left, parent);
if (tmp)
rb_set_parent_color(tmp, parent,
RB_BLACK);
rb_set_parent_color(parent, node, RB_RED);
augment_rotate(parent, node);
parent = node;
tmp = node->rb_right;
} /*
* Case 3 - node's uncle is black and node is
* the parent's left child (right rotate at gparent).
*
* G P
* / \ / \
* p U --> n g
* / \
* n U
*/
WRITE_ONCE(gparent->rb_left, tmp); /* == parent->rb_right */
WRITE_ONCE(parent->rb_right, gparent);
if (tmp)
rb_set_parent_color(tmp, gparent, RB_BLACK);
__rb_rotate_set_parents(gparent, parent, root, RB_RED);
augment_rotate(gparent, parent);
break;
} else {
tmp = gparent->rb_left;
if (tmp && rb_is_red(tmp)) {
/* Case 1 - color flips */
rb_set_parent_color(tmp, gparent, RB_BLACK);
rb_set_parent_color(parent, gparent, RB_BLACK);
node = gparent;
parent = rb_parent(node);
rb_set_parent_color(node, parent, RB_RED);
continue;
} tmp = parent->rb_left;
if (node == tmp) {
/* Case 2 - right rotate at parent */
tmp = node->rb_right;
WRITE_ONCE(parent->rb_left, tmp);
WRITE_ONCE(node->rb_right, parent);
if (tmp)
rb_set_parent_color(tmp, parent,
RB_BLACK);
rb_set_parent_color(parent, node, RB_RED);
augment_rotate(parent, node);
parent = node;
tmp = node->rb_left;
} /* Case 3 - left rotate at gparent */
WRITE_ONCE(gparent->rb_right, tmp); /* == parent->rb_left */
WRITE_ONCE(parent->rb_left, gparent);
if (tmp)
rb_set_parent_color(tmp, gparent, RB_BLACK);
__rb_rotate_set_parents(gparent, parent, root, RB_RED);
augment_rotate(gparent, parent);
break;
}
}
} /*
* Inline version for rb_erase() use - we want to be able to inline
* and eliminate the dummy_rotate callback there
*/
static __always_inline void ____rb_erase_color(struct rb_node *parent, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
{
struct rb_node *node = NULL, *sibling, *tmp1, *tmp2; while (true) {
/*
* Loop invariants:
* - node is black (or NULL on first iteration)
* - node is not the root (parent is not NULL)
* - All leaf paths going through parent and node have a
* black node count that is 1 lower than other leaf paths.
*/
sibling = parent->rb_right;
if (node != sibling) { /* node == parent->rb_left */
if (rb_is_red(sibling)) {
/*
* Case 1 - left rotate at parent
*
* P S
* / \ / \
* N s --> p Sr
* / \ / \
* Sl Sr N Sl
*/
tmp1 = sibling->rb_left;
WRITE_ONCE(parent->rb_right, tmp1);
WRITE_ONCE(sibling->rb_left, parent);
rb_set_parent_color(tmp1, parent, RB_BLACK);
__rb_rotate_set_parents(parent, sibling, root,
RB_RED);
augment_rotate(parent, sibling);
sibling = tmp1;
}
tmp1 = sibling->rb_right;
if (!tmp1 || rb_is_black(tmp1)) {
tmp2 = sibling->rb_left;
if (!tmp2 || rb_is_black(tmp2)) {
/*
* Case 2 - sibling color flip
* (p could be either color here)
*
* (p) (p)
* / \ / \
* N S --> N s
* / \ / \
* Sl Sr Sl Sr
*
* This leaves us violating 5) which
* can be fixed by flipping p to black
* if it was red, or by recursing at p.
* p is red when coming from Case 1.
*/
rb_set_parent_color(sibling, parent,
RB_RED);
if (rb_is_red(parent))
rb_set_black(parent);
else {
node = parent;
parent = rb_parent(node);
if (parent)
continue;
}
break;
}
/*
* Case 3 - right rotate at sibling
* (p could be either color here)
*
* (p) (p)
* / \ / \
* N S --> N sl
* / \ \
* sl Sr S
* \
* Sr
*
* Note: p might be red, and then both
* p and sl are red after rotation(which
* breaks property 4). This is fixed in
* Case 4 (in __rb_rotate_set_parents()
* which set sl the color of p
* and set p RB_BLACK)
*
* (p) (sl)
* / \ / \
* N sl --> P S
* \ / \
* S N Sr
* \
* Sr
*/
tmp1 = tmp2->rb_right;
WRITE_ONCE(sibling->rb_left, tmp1);
WRITE_ONCE(tmp2->rb_right, sibling);
WRITE_ONCE(parent->rb_right, tmp2);
if (tmp1)
rb_set_parent_color(tmp1, sibling,
RB_BLACK);
augment_rotate(sibling, tmp2);
tmp1 = sibling;
sibling = tmp2;
}
/*
* Case 4 - left rotate at parent + color flips
* (p and sl could be either color here.
* After rotation, p becomes black, s acquires
* p's color, and sl keeps its color)
*
* (p) (s)
* / \ / \
* N S --> P Sr
* / \ / \
* (sl) sr N (sl)
*/
tmp2 = sibling->rb_left;
WRITE_ONCE(parent->rb_right, tmp2);
WRITE_ONCE(sibling->rb_left, parent);
rb_set_parent_color(tmp1, sibling, RB_BLACK);
if (tmp2)
rb_set_parent(tmp2, parent);
__rb_rotate_set_parents(parent, sibling, root,
RB_BLACK);
augment_rotate(parent, sibling);
break;
} else {
sibling = parent->rb_left;
if (rb_is_red(sibling)) {
/* Case 1 - right rotate at parent */
tmp1 = sibling->rb_right;
WRITE_ONCE(parent->rb_left, tmp1);
WRITE_ONCE(sibling->rb_right, parent);
rb_set_parent_color(tmp1, parent, RB_BLACK);
__rb_rotate_set_parents(parent, sibling, root,
RB_RED);
augment_rotate(parent, sibling);
sibling = tmp1;
}
tmp1 = sibling->rb_left;
if (!tmp1 || rb_is_black(tmp1)) {
tmp2 = sibling->rb_right;
if (!tmp2 || rb_is_black(tmp2)) {
/* Case 2 - sibling color flip */
rb_set_parent_color(sibling, parent,
RB_RED);
if (rb_is_red(parent))
rb_set_black(parent);
else {
node = parent;
parent = rb_parent(node);
if (parent)
continue;
}
break;
}
/* Case 3 - left rotate at sibling */
tmp1 = tmp2->rb_left;
WRITE_ONCE(sibling->rb_right, tmp1);
WRITE_ONCE(tmp2->rb_left, sibling);
WRITE_ONCE(parent->rb_left, tmp2);
if (tmp1)
rb_set_parent_color(tmp1, sibling,
RB_BLACK);
augment_rotate(sibling, tmp2);
tmp1 = sibling;
sibling = tmp2;
}
/* Case 4 - right rotate at parent + color flips */
tmp2 = sibling->rb_right;
WRITE_ONCE(parent->rb_left, tmp2);
WRITE_ONCE(sibling->rb_right, parent);
rb_set_parent_color(tmp1, sibling, RB_BLACK);
if (tmp2)
rb_set_parent(tmp2, parent);
__rb_rotate_set_parents(parent, sibling, root,
RB_BLACK);
augment_rotate(parent, sibling);
break;
}
}
} /* Non-inline version for rb_erase_augmented() use */
void __rb_erase_color(struct rb_node *parent, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
{
____rb_erase_color(parent, root, augment_rotate);
}
//EXPORT_SYMBOL(__rb_erase_color); /*
* Non-augmented rbtree manipulation functions.
*
* We use dummy augmented callbacks here, and have the compiler optimize them
* out of the rb_insert_color() and rb_erase() function definitions.
*/ static inline void dummy_propagate(struct rb_node *node, struct rb_node *stop) {}
static inline void dummy_copy(struct rb_node *old, struct rb_node *new) {}
static inline void dummy_rotate(struct rb_node *old, struct rb_node *new) {} static const struct rb_augment_callbacks dummy_callbacks = {
.propagate = dummy_propagate,
.copy = dummy_copy,
.rotate = dummy_rotate
}; void rb_insert_color(struct rb_node *node, struct rb_root *root)
{
__rb_insert(node, root, dummy_rotate);
}
//EXPORT_SYMBOL(rb_insert_color); void rb_erase(struct rb_node *node, struct rb_root *root)
{
struct rb_node *rebalance;
rebalance = __rb_erase_augmented(node, root, &dummy_callbacks);
if (rebalance)
____rb_erase_color(rebalance, root, dummy_rotate);
}
//EXPORT_SYMBOL(rb_erase); /*
* Augmented rbtree manipulation functions.
*
* This instantiates the same __always_inline functions as in the non-augmented
* case, but this time with user-defined callbacks.
*/ void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
{
__rb_insert(node, root, augment_rotate);
}
//EXPORT_SYMBOL(__rb_insert_augmented); /*
* This function returns the first node (in sort order) of the tree.
*/
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;
}
//EXPORT_SYMBOL(rb_first); 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;
}
//EXPORT_SYMBOL(rb_last); struct rb_node *rb_next(const struct rb_node *node)
{
struct rb_node *parent; if (RB_EMPTY_NODE(node))
return NULL; /*
* If we have a right-hand child, go down and then left as far
* as we can.
*/
if (node->rb_right) {
node = node->rb_right;
while (node->rb_left)
node=node->rb_left;
return (struct rb_node *)node;
} /*
* No right-hand children. Everything down and left is smaller than us,
* so any 'next' node must be in the general direction of our parent.
* Go up the tree; any time the ancestor is a right-hand child of its
* parent, keep going up. First time it's a left-hand child of its
* parent, said parent is our 'next' node.
*/
while ((parent = rb_parent(node)) && node == parent->rb_right)
node = parent; return parent;
}
//EXPORT_SYMBOL(rb_next); struct rb_node *rb_prev(const struct rb_node *node)
{
struct rb_node *parent; if (RB_EMPTY_NODE(node))
return NULL; /*
* If we have a left-hand child, go down and then right as far
* as we can.
*/
if (node->rb_left) {
node = node->rb_left;
while (node->rb_right)
node=node->rb_right;
return (struct rb_node *)node;
} /*
* No left-hand children. Go up till we find an ancestor which
* is a right-hand child of its parent.
*/
while ((parent = rb_parent(node)) && node == parent->rb_left)
node = parent; return parent;
}
//EXPORT_SYMBOL(rb_prev); void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root)
{
struct rb_node *parent = rb_parent(victim); /* Copy the pointers/colour from the victim to the replacement */
*new = *victim; /* Set the surrounding nodes to point to the replacement */
if (victim->rb_left)
rb_set_parent(victim->rb_left, new);
if (victim->rb_right)
rb_set_parent(victim->rb_right, new);
__rb_change_child(victim, new, parent, root);
}
//EXPORT_SYMBOL(rb_replace_node); void rb_replace_node_rcu(struct rb_node *victim, struct rb_node *new, struct rb_root *root)
{
struct rb_node *parent = rb_parent(victim); /* Copy the pointers/colour from the victim to the replacement */
*new = *victim; /* Set the surrounding nodes to point to the replacement */
if (victim->rb_left)
rb_set_parent(victim->rb_left, new);
if (victim->rb_right)
rb_set_parent(victim->rb_right, new); /* Set the parent's pointer to the new node last after an RCU barrier
* so that the pointers onwards are seen to be set correctly when doing
* an RCU walk over the tree.
*/
__rb_change_child_rcu(victim, new, parent, root);
}
//EXPORT_SYMBOL(rb_replace_node_rcu); static struct rb_node *rb_left_deepest_node(const struct rb_node *node)
{
for (;;) {
if (node->rb_left)
node = node->rb_left;
else if (node->rb_right)
node = node->rb_right;
else
return (struct rb_node *)node;
}
} struct rb_node *rb_next_postorder(const struct rb_node *node)
{
const struct rb_node *parent;
if (!node)
return NULL;
parent = rb_parent(node); /* If we're sitting on node, we've already seen our children */
if (parent && node == parent->rb_left && parent->rb_right) {
/* If we are the parent's left node, go to the parent's right
* node then all the way down to the left */
return rb_left_deepest_node(parent->rb_right);
} else
/* Otherwise we are the parent's right node, and the parent
* should be next */
return (struct rb_node *)parent;
}
//EXPORT_SYMBOL(rb_next_postorder); struct rb_node *rb_first_postorder(const struct rb_root *root)
{
if (!root->rb_node)
return NULL; return rb_left_deepest_node(root->rb_node);
}
//EXPORT_SYMBOL(rb_first_postorder);

3. 测试文件

/*
* 使用 kernel 中的 rbtree_test.c 进行测试更好,其产生随机数据,并记录查找时间
*/
#include <stdio.h>
#include <stdlib.h>
#include "rbtree.h" struct test_node {
int key;
struct rb_node rb;
int val;
}; static struct rb_root_cached rbtree_root = RB_ROOT_CACHED;
static struct test_node *nodes = NULL; static void insert_cached(struct test_node *node, struct rb_root_cached *root)
{
struct rb_node **new = &root->rb_root.rb_node, *parent = NULL;
int key = node->key;
bool leftmost = true; while (*new) {
parent = *new;
if (key < rb_entry(parent, struct test_node, rb)->key) {
new = &parent->rb_left;
} else {
new = &parent->rb_right;
leftmost = false; //只要一次往右找了,新节点node就不可能是leftmost节点了
}
} rb_link_node(&node->rb, parent, new);
rb_insert_color_cached(&node->rb, root, leftmost);
} struct test_node *search_cached(struct rb_root_cached *root, int key) {
struct test_node *node_target = NULL;
struct rb_node **new = &root->rb_root.rb_node, *parent = NULL; while (*new) {
parent = *new;
node_target = rb_entry(parent, struct test_node, rb);
if (key < node_target->key) {
new = &parent->rb_left;
} else if (key > node_target->key) {
new = &parent->rb_right;
} else {
return node_target;
}
} return NULL;
} static void erase_cached(struct test_node *node, struct rb_root_cached *root)
{
rb_erase_cached(&node->rb, root);
    //free(node);
}

static void test_init(struct rb_root_cached *root, int num) {
int i, key, val; nodes = (struct test_node *)calloc(num, sizeof(struct test_node));
if (!nodes) {
exit(-1);
} printf("insert:\n");
for (i = 0; i < num; i++) {
key = rand() % (num * 100);
val = rand() % (num * 100);
nodes[i].key = key;
nodes[i].val = val;
insert_cached(&nodes[i], root);
printf("key=%d, val=%d\n", key, val);
}
} static void test_interator(struct rb_root_cached *root) {
struct test_node *pos, *n; printf("\ninterator:\n");
rbtree_postorder_for_each_entry_safe(pos, n, &root->rb_root, rb) {
printf("key=%d, val=%d\n", pos->key, pos->val);
} pos = container_of(root->rb_leftmost, struct test_node, rb);
printf("leftmost->key=%d, leftmost->val=%d\n", pos->key, pos->val);
} static void test_interator_self_define(struct rb_root_cached *root) {
struct rb_node *rn;
struct test_node *pos; printf("\nspecial_pos:\n");
rn = rb_first(&root->rb_root);
pos = container_of(rn, struct test_node, rb);
printf("first: key=%d, val=%d\n", pos->key, pos->val); rn = rb_next(rn);
pos = container_of(rn, struct test_node, rb);
printf("next: key=%d, val=%d\n", pos->key, pos->val); rn = rb_last(&root->rb_root);
pos = container_of(rn, struct test_node, rb);
printf("last: key=%d, val=%d\n", pos->key, pos->val); rn = rb_prev(rn);
pos = container_of(rn, struct test_node, rb);
printf("prev: key=%d, val=%d\n", pos->key, pos->val); printf("\ninterator_self:\n");
rn = rb_first(&root->rb_root);
while(rn) {
rn = rb_next(rn);
if (rn) {
pos = container_of(rn, struct test_node, rb);
printf("key=%d, val=%d\n", pos->key, pos->val);
}
}
} static void test_search_erase(struct rb_root_cached *root, int num)
{
int i;
struct test_node *node; //删除key值落在前50%的节点
printf("\ndelete:\n");
for (i = 0; i < num * 100 / 2; i++) {
node = search_cached(root, i);
if (node) {
printf("key=%d, val=%d\n", node->key, node->val);
erase_cached(node, root);
}
}
} int main(int argc, char *argv[])
{
int num = 100; if (argc == 2) {
num = atoi(argv[1]);
} test_init(&rbtree_root, num);
test_interator(&rbtree_root);
test_interator_self_define(&rbtree_root);
test_search_erase(&rbtree_root, num);
test_interator(&rbtree_root); free(nodes); return 0;
}

实验结果:

/*
$ ./pp 10
insert:
key=383, val=886
key=777, val=915
key=793, val=335
key=386, val=492
key=649, val=421
key=362, val=27
key=690, val=59
key=763, val=926
key=540, val=426
key=172, val=736 interator:
key=172, val=736
key=383, val=886
key=362, val=27
key=540, val=426
key=649, val=421
key=386, val=492
key=763, val=926
key=793, val=335
key=777, val=915
key=690, val=59
leftmost->key=172, leftmost->val=736 special_pos:
first: key=172, val=736
next: key=362, val=27
last: key=793, val=335
prev: key=777, val=915 interator_self:
key=362, val=27
key=383, val=886
key=386, val=492
key=540, val=426
key=649, val=421
key=690, val=59
key=763, val=926
key=777, val=915
key=793, val=335 delete:
key=172, val=736
key=362, val=27
key=383, val=886
key=386, val=492 interator:
key=649, val=421
key=540, val=426
key=763, val=926
key=793, val=335
key=777, val=915
key=690, val=59
leftmost->key=540, leftmost->val=426
*/

4. 总结

使用 rbtree_postorder_for_each_entry_safe 这个宏遍历输出的值并非是按key的大小排序的,但是使用 rb_first 和 rb_next 获取到的是按 key 值大小排序的。

5. 补充

1. 插入时也可以不指定key,通过比较地址找到插入位置,举例如下。查找时可以通过 test_info 结构中的某个成员作为 key 进行查找。

//还可以没有key,直接使用地址作为key进行对比
void test_info_add(struct render_info *thr)
{
struct rb_node **p = &test_info_tree.rb_node;
struct rb_node *parent = NULL;
struct test_info *tmp = NULL; while (*p) {
parent = *p;
tmp = rb_entry(parent, struct render_info, linger_node);
if (thr < tmp)
p = &(*p)->rb_left;
else if (thr > tmp)
p = &(*p)->rb_right;
else {
return; //在红黑树中就直接返回了
}
} rb_link_node(&thr->linger_node, parent, p);
rb_insert_color(&thr->linger_node, &test_info_tree);
}

Linux内核红黑树2—移植笔记的更多相关文章

  1. 详解Linux内核红黑树算法的实现

    转自:https://blog.csdn.net/npy_lp/article/details/7420689 内核源码:linux-2.6.38.8.tar.bz2 关于二叉查找树的概念请参考博文& ...

  2. 红黑树(三)之 Linux内核中红黑树的经典实现

    概要 前面分别介绍了红黑树的理论知识 以及 通过C语言实现了红黑树.本章继续会红黑树进行介绍,下面将Linux 内核中的红黑树单独移植出来进行测试验证.若读者对红黑树的理论知识不熟悉,建立先学习红黑树 ...

  3. Linux内核设计与实现 读书笔记 转

    Linux内核设计与实现  读书笔记: http://www.cnblogs.com/wang_yb/tag/linux-kernel/ <深入理解LINUX内存管理> http://bl ...

  4. linux 3.4.103 内核移植到 S3C6410 开发板 移植失败 (问题总结,日本再战!)

    linux 3.4.103 内核移植到 S3C6410 开发板 这个星期差点儿就搭在这里面了,一開始感觉非常不值得,移植这样的浪费时间的事情.想立刻搞定,然后安安静静看书 & coding. ...

  5. Linux内核分析第二周学习笔记

    linux内核分析第二周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  6. 三十道linux内核面试题

      1. Linux中主要有哪几种内核锁? Linux的同步机制从2.0到2.6以来不断发展完善.从最初的原子操作,到后来的信号量,从大内核锁到今天的自旋锁.这些同步机制的发展伴随Linux从单处理器 ...

  7. LINUX内核面试题摘选

    转载:http://blog.csdn.net/zm1_1zm/article/details/77231197 1) Linux中主要有哪几种内核锁? 答:Linux的同步机制从2.0到2.6以来不 ...

  8. Linux内网渗透

    Linux虽然没有域环境,但是当我们拿到一台Linux 系统权限,难道只进行一下提权,捕获一下敏感信息就结束了吗?显然不只是这样的.本片文章将从拿到一个Linux shell开始,介绍Linux内网渗 ...

  9. Linux Shell脚本攻略 读书笔记

    Linux Shell脚本攻略 读书笔记 这是一本小书,总共253页,但内容却很丰富,书中的示例小巧而实用,对我这样总是在shell门前徘徊的人来说真是如获至宝:最有价值的当属文本处理,对这块我单独整 ...

  10. 卸载Linux内置的AMP软件

    卸载Linux内置的AMP软件 在安装Linux软件的LAMP环境时,必须有一个前提:必须要完全卸载掉系统内置的AMP软件. 1.卸载httpd软件(Apache) 如果在卸载软件时出现依赖关系,我们 ...

随机推荐

  1. 微服务学习计划——SpringCloud

    微服务学习计划--SpringCloud 在学习并掌握了众多基础框架之后,我们的项目繁杂且难以掌握,那么我们就需要开启一门新的课程,也就是我们常说的微服务架构 随着互联网行业的发展,对服务的要求也越来 ...

  2. mybatis学习日记

    1.什么是框架 框架是软件开发中的一套解决方案,不同的框架解决不同的问题 2.三层架构 表现层:展示数据 业务层:处理业务需求 持久层:与数据库交互 3.持久层解决技术 JDBC技术(JDBC是一种规 ...

  3. JZOJ 4496. 【GDSOI 2016】第一题 互补约数

    \(\text{Problem}\) 求 \[\sum_{i=1}^n \sum_{d|n} \gcd(d, \frac{i}{d}) \] 有 \(n \le 10^{11}\) \(\text{A ...

  4. ubuntu18.04 server版安装教程

    转载博客园: Ubuntu18.04 Server版安装(详细版) - 运维密码 - 博客园 (cnblogs.com)

  5. python爬取网页的多种方式以及保存方法

    爬取网页信息并保存 bs4和lxml都是用来将接收的数据解析html 1.bs4+excel(openpyxl): import requests from bs4 import BeautifulS ...

  6. left join(一)

    例表aaid adate1 a12 a23 a3 表bbid bdate1 b12 b24 b4 两个表a,b相连接,要取出id相同的字段select * from a inner join b on ...

  7. EF Corexxxxnstance with the same key value for {'Id'} is already being tracked.

    AsNoTracki或者全局禁用 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { // ...

  8. lg8365题解

    容易发现我们一定会先加后乘,使用调整法可以证明这个结论. 并且可以发现除了\(a_i\)值为\(1\)的数外(假设他们的\(a\)值和为\(s\)),其他的数最多只会选\(1\)个做加法操作(设如果其 ...

  9. accessservice对于难定位的view如何定位

    private static int tabcount = -1; private static StringBuilder sb; public static void printPacketInf ...

  10. 初始化控件panel大小和相对父容器居中

    /// <summary> /// 初始化界面大小 /// </summary> protected void InitForm() { int winwith = Scree ...