说明:
1.nginx红黑树除了是个通用结构体,还是定时器实现的载体,进一步学习定时器代码需要了解红黑树用法;
2.nginx红黑树基本上只提供了一个初始化红黑树、增、删节点,查找最小节点四种操作,其实对nginx也够了;
3.nginx红黑树细节暴露比较多,节点要自己malloc自己构造,插入操作的第一步(旋转前)要自己实现(尽管各种实现的不同处都只是在key相同时提供比较大小的方法),节点删除后要自己释放(当然有内存池要方便不少),树结构不要了也要自己释放;
4.因为是内部使用,没有异常检查。
综上,打算扒出来代码改点(主要是增加key比较逻辑),之后封装完全隐藏细节并构造、析构统一化,顺便加点注释,进行基本测试。本质还是要在改的过程中学习代码。
修改之后的核心代码,mytool_rbtree_raw.h
#ifndef MYTOOL_RBTREE_RAW_H
#define MYTOOL_RBTREE_RAW_H
namespace mytool{
typedef bool (*smallerFun)(void *,void *);
struct rbtree_node_t{
unsigned key;
rbtree_node_t *left;
rbtree_node_t *right;
rbtree_node_t *parent;
unsigned char color;
unsigned char data;
};
struct rbtree_t{
rbtree_node_t *root;
rbtree_node_t *sentinel;
smallerFun sfun;
};
#define rbtree_init(tree, s, i) \
rbtree_sentinel_init(s); \
(tree)->root = s; \
(tree)->sentinel = s; \
(tree)->sfun = i
void rbtree_insert(rbtree_t *tree,rbtree_node_t *node);
void rbtree_delete(rbtree_t *tree,rbtree_node_t *node);
//默认insert函数,已无必要
//void rbtree_insert_value(rbtree_node_t *root,rbtree_node_t *node,rbtree_node_t *sentinel);
//timer的insert函数,已无必要
//void rbtree_insert_timer_value(rbtree_node_t *root,rbtree_node_t *node,rbtree_node_t *sentinel);
//原代码对于timer对比没有相等的情况,可惜这个inline还是可能得变成函数指针
inline bool timer_smaller(void *p1,void *p2){return true;}
#define rbt_red(node) ((node)->color = 1)
#define rbt_black(node) ((node)->color = 0)
#define rbt_is_red(node) ((node)->color)
#define rbt_is_black(node) (!rbt_is_red(node))
#define rbt_copy_color(n1, n2) (n1->color = n2->color)
#define rbtree_sentinel_init(node) rbt_black(node)
static inline rbtree_node_t *rbtree_min(rbtree_node_t *node,rbtree_node_t *sentinel){
while(node->left != sentinel)
node = node->left;
return node;
}
}
#endif
mytool_rbtree_raw.cpp
#include "mytool_rbtree_raw.h"
#include <cstdlib> //for NULL
namespace mytool{
static inline void rbtree_left_rotate(rbtree_node_t **root,rbtree_node_t *sentinel,rbtree_node_t *node);
static inline void rbtree_right_rotate(rbtree_node_t **root,rbtree_node_t *sentinel,rbtree_node_t *node);
void rbtree_insert(rbtree_t *tree,rbtree_node_t *node)
{
rbtree_node_t **root,*temp,*sentinel;
/* a binary tree insert */
root = (rbtree_node_t **)&tree->root;
sentinel = tree->sentinel;
if(*root == sentinel){
node->parent = NULL;
node->left = sentinel;
node->right = sentinel;
rbt_black(node);
*root = node;
return;
}
//之前的insert需要重新实现,但其实只有key相等的部分需要,其他的比如迭代过程收尾过程都是一样的,所以在此把insert函数改成了一个smallFun只比data大小的
//tree->insert(*root, node, sentinel);
{
rbtree_node_t **p;
rbtree_node_t *temp = *root;
for(;;){
if(node->key < temp->key){
p = &temp->left;
}else if(node->key > temp->key){
p = &temp->right;
}else if(tree->sfun(&(node->data),&(temp->data))){
p = &temp->left;
}else{
p = &temp->right;
}
if(*p == sentinel)
break;
temp = *p;
}
*p = node;
node->parent = temp;
node->left = sentinel;
node->right = sentinel;
rbt_red(node);
}
/* re-balance tree */
while(node != *root && rbt_is_red(node->parent)){
if(node->parent == node->parent->parent->left){
temp = node->parent->parent->right;
if(rbt_is_red(temp)){
rbt_black(node->parent);
rbt_black(temp);
rbt_red(node->parent->parent);
node = node->parent->parent;
}else{
if(node == node->parent->right){
node = node->parent;
rbtree_left_rotate(root, sentinel, node);
}
rbt_black(node->parent);
rbt_red(node->parent->parent);
rbtree_right_rotate(root, sentinel, node->parent->parent);
}
}else{
temp = node->parent->parent->left;
if(rbt_is_red(temp)){
rbt_black(node->parent);
rbt_black(temp);
rbt_red(node->parent->parent);
node = node->parent->parent;
}else{
if(node == node->parent->left){
node = node->parent;
rbtree_right_rotate(root, sentinel, node);
}
rbt_black(node->parent);
rbt_red(node->parent->parent);
rbtree_left_rotate(root, sentinel, node->parent->parent);
}
}
}
rbt_black(*root);
}
/*
void rbtree_insert_value(rbtree_node_t *temp,rbtree_node_t *node,rbtree_node_t *sentinel){
rbtree_node_t **p;
for(;;){
p = (node->key < temp->key) ? &temp->left : &temp->right;
if(*p == sentinel)
break;
temp = *p;
}
*p = node;
node->parent = temp;
node->left = sentinel;
node->right = sentinel;
rbt_red(node);
}
*/
void rbtree_delete(rbtree_t *tree,rbtree_node_t *node){
unsigned red;
rbtree_node_t **root,*sentinel,*subst,*temp,*w;
/* a binary tree delete */
root = (rbtree_node_t **)&tree->root;
sentinel = tree->sentinel;
if (node->left == sentinel){
temp = node->right;
subst = node;
}else if(node->right == sentinel){
temp = node->left;
subst = node;
}else{
subst = rbtree_min(node->right, sentinel);
if(subst->left != sentinel){
temp = subst->left;
}else{
temp = subst->right;
}
}
if(subst == *root){
*root = temp;
rbt_black(temp);
/* DEBUG stuff */
node->left = NULL;
node->right = NULL;
node->parent = NULL;
node->key = 0;
return;
}
red = rbt_is_red(subst);
if(subst == subst->parent->left){
subst->parent->left = temp;
}else{
subst->parent->right = temp;
}
if(subst == node){
temp->parent = subst->parent;
}else{
if(subst->parent == node){
temp->parent = subst;
}else{
temp->parent = subst->parent;
}
subst->left = node->left;
subst->right = node->right;
subst->parent = node->parent;
rbt_copy_color(subst, node);
if(node == *root){
*root = subst;
}else{
if(node == node->parent->left){
node->parent->left = subst;
}else{
node->parent->right = subst;
}
}
if(subst->left != sentinel)
subst->left->parent = subst;
if(subst->right != sentinel)
subst->right->parent = subst;
}
/* DEBUG stuff */
node->left = NULL;
node->right = NULL;
node->parent = NULL;
node->key = 0;
if(red)
return;
/* a delete fixup */
while(temp != *root && rbt_is_black(temp)){
if(temp == temp->parent->left){
w = temp->parent->right;
if(rbt_is_red(w)){
rbt_black(w);
rbt_red(temp->parent);
rbtree_left_rotate(root,sentinel,temp->parent);
w = temp->parent->right;
}
if(rbt_is_black(w->left) && rbt_is_black(w->right)){
rbt_red(w);
temp = temp->parent;
}else{
if(rbt_is_black(w->right)){
rbt_black(w->left);
rbt_red(w);
rbtree_right_rotate(root,sentinel,w);
w = temp->parent->right;
}
rbt_copy_color(w,temp->parent);
rbt_black(temp->parent);
rbt_black(w->right);
rbtree_left_rotate(root,sentinel,temp->parent);
temp = *root;
}
}else{
w = temp->parent->left;
if(rbt_is_red(w)){
rbt_black(w);
rbt_red(temp->parent);
rbtree_right_rotate(root,sentinel,temp->parent);
w = temp->parent->left;
}
if(rbt_is_black(w->left) && rbt_is_black(w->right)){
rbt_red(w);
temp = temp->parent;
}else{
if(rbt_is_black(w->left)){
rbt_black(w->right);
rbt_red(w);
rbtree_left_rotate(root,sentinel,w);
w = temp->parent->left;
}
rbt_copy_color(w, temp->parent);
rbt_black(temp->parent);
rbt_black(w->left);
rbtree_right_rotate(root,sentinel,temp->parent);
temp = *root;
}
}
}
rbt_black(temp);
}
static inline void rbtree_left_rotate(rbtree_node_t **root,rbtree_node_t *sentinel,rbtree_node_t *node){
rbtree_node_t *temp;
temp = node->right;
node->right = temp->left;
if(temp->left != sentinel)
temp->left->parent = node;
temp->parent = node->parent;
if(node == *root){
*root = temp;
}else if(node == node->parent->left){
node->parent->left = temp;
}else{
node->parent->right = temp;
}
temp->left = node;
node->parent = temp;
}
static inline void rbtree_right_rotate(rbtree_node_t **root,rbtree_node_t *sentinel,rbtree_node_t *node){
rbtree_node_t *temp;
temp = node->left;
node->left = temp->right;
if(temp->right != sentinel)
temp->right->parent = node;
temp->parent = node->parent;
if(node == *root){
*root = temp;
}else if(node == node->parent->right){
node->parent->right = temp;
}else{
node->parent->left = temp;
}
temp->right = node;
node->parent = temp;
}
}
核心代码基本测试代码:
#include "mytool_rbtree_raw.h"
#include <cstring>
#include <cstdio>
using namespace mytool;
struct person{
struct rbtree_node_t node;
char namePad[30];
};
int main(){
struct rbtree_t rbt;
struct rbtree_node_t sentinel,*prn;
memset(&sentinel,sizeof(sentinel),0);
rbtree_init(&rbt,&sentinel,timer_smaller);
struct person n1,n2,n3,n4;
n1.node.key = 11;
n2.node.key = 22;
n3.node.key = 33;
n4.node.key = 44;
strcpy((char *)(&(n1.node.data)),"once");
strcpy((char *)(&(n2.node.data)),"veintidos");
strcpy((char *)(&(n3.node.data)),"treinta y tres");
strcpy((char *)(&(n4.node.data)),"cuarenta y cuatro");
rbtree_insert(&rbt,&(n4.node));
rbtree_insert(&rbt,&(n3.node));
rbtree_insert(&rbt,&(n2.node));
rbtree_insert(&rbt,&(n1.node));
int i = 4;
while(i > 0){
prn = rbtree_min(rbt.root,rbt.sentinel);
printf("%dth——key:%u,name:%s\n",i,prn->key,(char *)(&(prn->data)));
rbtree_delete(&rbt,prn);
i--;
}
}
封装头文件:
mytool_rbtree.h
#ifndef MYTOOL_RBTREE_H
#define MYTOOL_RBTREE_H
#include <cstddef>
namespace mytool{
//特化的红黑树,操作只支持求最小的节点
class Rbtree{
typedef bool (*smallerFun)(void *,void *);
public:
//fun不能为NULL
//异常:out_of_memory,invalid_argument
explicit Rbtree(smallerFun fun) noexcept(false) {
_initPrb(fun);
}
//data其实可以为NULL,如果data全部为NULL就退化成了set,所以data还是不能为NULL,所以size不能为0
//为了防止数据拷贝到node内部的开销,要求使用者使用getNodeData动态获取内存,node的头结构隐藏在了返回指针的前面
//返回指针已经考虑到了对齐
//异常:out_of_memory,invalid_argument
void *getNodeData(size_t size) const noexcept(false);
//异常:logic_error
void insertNodeData(void *data,unsigned key) const noexcept(false);
//异常:invalid_argument,logic_error
//每个红黑树可以增加一个全局的编号,来验证要删除的data是不是本树的,未实现,靠调用者保证
void deleteNodeData(void *data) const noexcept(false);
void *getMinData() const noexcept;
//删除节点一直到空,并且删除_prb
~Rbtree() noexcept;
private:
void _initPrb(smallerFun fun) noexcept(false);
void *_prb;
};
}
#endif
mytool_rbtree.cpp
#include "mytool_rbtree.h"
#include "mytool_rbtree_raw.h"
#include <stdexcept>
#include <cstring>
#define RBTREEP(p) ((struct rbtree_t *)(p))
#define RBTREENODEP(p) ((struct rbtree_node_t *)(p))
#define NODEMAGIC 88
#define ALIGNSIZE 16
#define NODEALIGNEDSIZE ((sizeof(struct rbtree_node_t) + ALIGNSIZE - 1) & ~(ALIGNSIZE - 1))
namespace mytool{
void Rbtree::_initPrb(smallerFun fun) noexcept(false){
if(fun == NULL)
throw std::invalid_argument("smallerFun can not be empty");
//用new不用malloc因为new能够有分配失败策略,再失败直接抛异常
//尽管是new char,也是按照最大对齐规则的
_prb = (void *)(new char[sizeof(struct rbtree_t)]);
struct rbtree_node_t *psentinel = RBTREENODEP(new char[sizeof(struct rbtree_node_t)]);
rbtree_init(RBTREEP(_prb),psentinel,fun);
}
void *Rbtree::getNodeData(size_t size) const noexcept(false){
if(size == 0)
throw std::invalid_argument("size can not be zero");
struct rbtree_node_t *prn = RBTREENODEP(new char[NODEALIGNEDSIZE + size]);
memset(prn,0,NODEALIGNEDSIZE);
//隐藏rbtree_node_t细节后可以加一个魔数验证传的到底是不是node的data,这里用已经没有用了的data字段
prn->data = NODEMAGIC;
//color用来表示是否已经加入过node,当前合法color只有0,1
prn->color = NODEMAGIC;
return (char *)prn + NODEALIGNEDSIZE;
}
void Rbtree::insertNodeData(void *data,unsigned key) const noexcept(false){
if(data == NULL)
return;
struct rbtree_node_t *prn = RBTREENODEP((char *)data - NODEALIGNEDSIZE);
if(prn->data != NODEMAGIC)
throw std::logic_error("data is not a valid node");
if(prn->color != NODEMAGIC)
throw std::logic_error("data has been added before");
struct rbtree_t *pr = RBTREEP(_prb);
prn->key = key;
//底层代码没细看,说不定有坑
rbtree_insert(pr,prn);
}
void Rbtree::deleteNodeData(void *data) const noexcept(false){
struct rbtree_node_t *prn = RBTREENODEP((char *)data - NODEALIGNEDSIZE);
if(data == NULL)
return;
if(prn->data != NODEMAGIC)
throw std::logic_error("data is not a valid node");
struct rbtree_t *pr = RBTREEP(_prb);
rbtree_delete(pr,prn);
delete [] (char *)prn;
}
void *Rbtree::getMinData() const noexcept{
struct rbtree_t *pr = RBTREEP(_prb);
if(pr->root == pr->sentinel)
return NULL;
struct rbtree_node_t *prn = rbtree_min(pr->root,pr->sentinel);
return (char *)prn + NODEALIGNEDSIZE;
}
Rbtree::~Rbtree(){
void *p = getMinData();
while(p != NULL){
deleteNodeData(p);
p = getMinData();
}
delete [] (char *)_prb;
}
}
封装基本测试,testTree.cpp:
#include "mytool_rbtree.h"
#include <iostream>
using namespace mytool;
bool smallerInt(void *p1,void *p2){
return *((int *)p1) < *((int *)p1);
}
int main(){
Rbtree r(smallerInt);
int *p1,*p2,*p3,*p4;
p1 = (int *)r.getNodeData(sizeof(int));
p2 = (int *)r.getNodeData(sizeof(int));
p3 = (int *)r.getNodeData(sizeof(int));
p4 = (int *)r.getNodeData(sizeof(int));
*p1 = 11;
*p2 = 22;
*p3 = 33;
*p4 = 44;
r.insertNodeData(p3,33);
r.insertNodeData(p2,22);
r.insertNodeData(p4,44);
r.insertNodeData(p1,11);
int *p = (int *)r.getMinData();
while(p != NULL){
std::cout<<*p<<std::endl;
r.deleteNodeData(p);
p = (int *)(r.getMinData());
}
}