这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战
红黑树由于节点颜色的特性,保证其是一种自平衡的二叉搜索树。 但其和Balanced Binary Trees之类的不同,包含一个标记颜色的数据。 它的各种约束条件使得从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。 红黑树虽然实现起来比较复杂,但性能不错,所以红黑树在内核中的应用非常广泛。 红黑树可以运用到以下场景
-
散列表的冲突处理
在节点多的时候红黑树效率高。在节点少的时候,链表方式则更为方便。
-
动态插入、删除和查询较多的场景。
一般而言,红黑树可以提供一下接口:
void RBTree_Init(RBTree *rbt); //初始化红黑树
void RBTree_Destroy(RBTree *rbt); //销毁红黑树
RBTreeNode * RBTree_First(const RBTree *rbt); //获取第一个结点
RBTreeNode * RBTree_Next(const RBTreeNode *node); //获取下一个结点
RBTreeNode * RBTree_Search(RBTree* rbt, int key); //红黑树查找结点
void* RBTree_GetData(RBTree* rbt, int key); //红黑树查找结点并获取该 结点数据
RBTreeNode * RBTree_Insert(RBTree *rbt, int key, void *data); //插入新的结点
int RBTree_Erase(RBTree *rbt, int key); //删除红黑树中的结点
void RBTree_EraseNode(RBTree *rbt, RBTreeNode *node); //按结点删除红黑树
int RBTree_CustomErase(RBTree *rbt, const void *keydata); //按指定数据删除结点
RBTreeNode * RBTree_CustomSearch(RBTree* rbt, const void *keydata); //红黑树按指定数据查找结点
void* RBTree_CustomGetData(RBTree* rbt, const void *keydata); //获取指定结点数据
RBTreeNode * RBTree_CustomInsert(RBTree *rbt, const void *keydata, void *data); //按指定数据插入
结构设计
下面的结构参照nginx的结构设计
struct rbtree_node_t_ {
unsigned int key;
rbtree_node_t *left;
rbtree_node_t *right;
rbtree_node_t *parent;
unsigned char color;
void *data;
};
这里可以和 Linux 中的节点结构设计比较一下
struct rb_node
{
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))));
可以看出,多出了 key 和 parent,这是由于 Linux 的字段 rb_parent_color 同时保存了父节点的地址和本节点的颜色两个信息。(利用内存对齐的特点)。