热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

nginx的数据结构3——扩展红黑树

:本篇文章主要介绍了nginx的数据结构3——扩展红黑树,对于PHP教程有兴趣的同学可以参考一下。
发扬我一贯的支线任务狂魔的作风,一晚上就完成了之前设想的红黑树扩展版本。

rbtree.h:

/*
 * Copyright (C) Bipedal Bit
 * Verson 1.0.0.2
 */

#ifndef _RBTREE_H_INCLUDED_
#define _RBTREE_H_INCLUDED_

/* the node structure of the red-black tree */
typedef struct rbtree_node_s rbtree_node_t;
/* Using type int means its range is -0x7fffffff-1~0x7fffffff. */
typedef int rbtree_key_t;
/* Abstract type is complicated to achieve with C so I use char* instead. */
typedef char* rbtree_data_t;

struct rbtree_node_s
{
	/* key of the node */
	rbtree_key_t	key;
	/* pointer of the parent of the node */
	rbtree_node_t*	parent;
	/* pointer of the left kid of the node */
	rbtree_node_t*	left;
	/* pointer of the right kid of the node */
	rbtree_node_t*	right;
	/* color of the node */
	unsigned char	color;
	/* pointer of the value of the node corresponding to the key */
	rbtree_data_t	value;
	/* count of nodes in the subtree whose root is the current node */
	int node_cnt;
};

/* the tree object stucture of the red-black tree */
typedef struct rbtree_s rbtree_t;
/* foundational insert function pointer */
typedef void (*rbtree_insert_p) (rbtree_t* root, rbtree_node_t* node);
/* foundational visit function pointer */
typedef void (*rbtree_visit_p) (rbtree_node_t* node);

struct rbtree_s
{
	/* the pointer of the root node of the tree */
	rbtree_node_t* root;
	/* black leaf nodes as sentinel */
	rbtree_node_t* sentinel;
	/* the polymorphic insert function pointer */
	rbtree_insert_p insert;
};

/* macros */
#define rbtree_init(tree, s, i)		\
rbtree_sentinel_init(s);			\
(tree)->root = s;				\
(tree)->sentinel = s;			\
(tree)->insert = i

#define rbtree_red(node)	((node)->color = 1)
#define rbtree_black(node)	((node)->color = 0)
#define rbtree_is_red(node)	((node)->color)
#define rbtree_is_black(node)	(!rbtree_is_red(node))
 /* copy n2's color to n1 */
#define rbtree_copy_color(n1, n2)	(n1->color = n2->color)
/* sentinel must be black cuz it's leaf node */
#define rbtree_sentinel_init(node)	\
rbtree_black(node);			\
(node)->node_cnt = 0

/* statements of public methods */
void rbtree_insert_value(rbtree_t* tree, rbtree_node_t* node);
void rbtree_insert(rbtree_t* tree, rbtree_node_t* node);
void rbtree_delete(rbtree_t* tree, rbtree_node_t* node);
/* get node by key */
rbtree_node_t* rbtree_find(rbtree_t* tree, rbtree_key_t key);
/* get node by order number */
rbtree_node_t* rbtree_index(rbtree_t* tree, int index);
int rbtree_height(rbtree_t* tree, rbtree_node_t* node);
int rbtree_count(rbtree_t* tree);
void rbtree_visit(rbtree_node_t* node);
void rbtree_traversal(rbtree_t* tree, rbtree_node_t* node, rbtree_visit_p);

#endif	/* _RBTREE_H_INCLUDED_ */
可以看到,我增加了按序号查找结点、求树高、求结点数、可重写访问节点方法的遍历,这么几个功能。

为了提高按序号查找结点的效率,我增加了一个结点项node_cnt,代表当前结点为根的子树上的结点总数。这样按序号查找结点的过程将是一个二分查找,时间效率与按key查找相同,都是O(log2n)。

遍历方法使用递归的中序遍历,默认的结点访问方法是个空方法,用户可以自行重写。

rbtree.c:

/*
 * Copyright (C) Bipedal Bit
 * Verson 1.0.0.2
 */

#include 
#include "rbtree.h"

/* inline methods */
/* get the node with the minimum key in a subtree of the red-black tree */
static inline rbtree_node_t*
rbtree_subtree_min(rbtree_node_t* node, rbtree_node_t* sentinel)
{
    while(node->left != sentinel)
    {
        node = node->left;
    }

    return node;
}

/* replace the node "node" in the tree with node "tmp" */
static inline void rbtree_replace(rbtree_t* tree,
    rbtree_node_t* node, rbtree_node_t* tmp)
{
&#160;&#160; &#160;/* upward: p[node] <- p[tmp] */
&#160;&#160; &#160;tmp->parent = node->parent;

&#160;&#160; &#160;if (node == tree->root)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;tree->root = tmp;
&#160;&#160; &#160;}
&#160;&#160; &#160;else if (node == node->parent->left)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;/* downward: left[p[node]] <- tmp */
&#160;&#160; &#160;&#160;&#160; &#160;node->parent->left = tmp;
&#160;&#160; &#160;}
&#160;&#160; &#160;else
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;/* downward: right[p[node]] <- tmp */
&#160;&#160; &#160;&#160;&#160; &#160;node->parent->right = tmp;
&#160;&#160; &#160;}

&#160;&#160; &#160;node->parent = tmp;
}

/* change the topologic structure of the tree keeping the order of the nodes */
static inline void rbtree_left_rotate(rbtree_t* tree, rbtree_node_t* node)
{
&#160;&#160; &#160;/* node as the var x in CLRS while tmp as the var y */
&#160;&#160; &#160;rbtree_node_t* tmp = node->right;

&#160;&#160; &#160;/* fix node_cnt */
&#160;&#160; &#160;node->node_cnt = node->left->node_cnt + tmp->left->node_cnt + 1;
&#160;&#160; &#160;tmp->node_cnt = node->node_cnt + tmp->right->node_cnt + 1;

&#160;&#160; &#160;/* replace y with left[y] */
&#160;&#160; &#160;/* downward: right[x] <- left[y] */
&#160;&#160; &#160;node->right = tmp->left;
&#160;&#160; &#160;/* if left[[y] is not NIL it has a parent */
&#160;&#160; &#160;if (tmp->left != tree->sentinel)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;/* upward: p[left[y]] <- x */
&#160;&#160; &#160;&#160;&#160; &#160;tmp->left->parent = node;
&#160;&#160; &#160;}

&#160;&#160; &#160;/* replace x with y */
&#160;&#160; &#160;rbtree_replace(tree, node, tmp);
&#160;&#160; &#160;tmp->left = node;
}

static inline void rbtree_right_rotate(rbtree_t* tree, rbtree_node_t* node)
{
&#160;&#160; &#160;rbtree_node_t* tmp = node->left;

&#160;&#160; &#160;/* fix node_cnt */
&#160;&#160; &#160;node->node_cnt = node->right->node_cnt + tmp->right->node_cnt + 1;
&#160;&#160; &#160;tmp->node_cnt = node->node_cnt + tmp->left->node_cnt + 1;

&#160;&#160; &#160;/* replace y with right[y] */
&#160;&#160; &#160;node->left = tmp->right;
&#160;&#160; &#160;if (tmp->right != tree->sentinel)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;tmp->right->parent = node;
&#160;&#160; &#160;}

&#160;&#160; &#160;/* replace x with y */
&#160;&#160; &#160;rbtree_replace(tree, node, tmp);
&#160;&#160; &#160;tmp->right = node;
}

/* static methods */
/* fix the red-black tree after the new node inserted */
static void rbtree_insert_fixup(rbtree_t* tree, rbtree_node_t* node)
{
&#160;&#160; &#160;while(rbtree_is_red(node->parent))
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;if (node->parent == node->parent->parent->left)
&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;/* case 1: node&#39;s uncle is red */
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;if (rbtree_is_red(node->parent->parent->right))
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(node->parent->parent->right);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_red(node->parent->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;node = node->parent->parent;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;/* Then we can consider the whole subtree */
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;/* which is represented by the new "node" as the "node" before */
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;/* and keep looping till "node" become the root. */
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;/* case 2: node&#39;s uncle is black */
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;else
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;/* ensure node is the left kid of its parent */
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;if (node == node->parent->right)
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;node = node->parent;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_left_rotate(tree, node);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;/* case 2 -> case 1 */
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_red(node->parent->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_right_rotate(tree, node->parent->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;/* same as the "if" clause before with "left" and "right" exchanged */
&#160;&#160; &#160;&#160;&#160; &#160;else
&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;if (rbtree_is_red(node->parent->parent->left))
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(node->parent->parent->left);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_red(node->parent->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;node = node->parent->parent;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;else
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;if (node == node->parent->left)
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;node = node->parent;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_right_rotate(tree, node);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_red(node->parent->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_left_rotate(tree, node->parent->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;}
&#160;&#160; &#160;/* ensure the root node being black */
&#160;&#160; &#160;rbtree_black(tree->root);
}

static void rbtree_delete_fixup(rbtree_t* tree, rbtree_node_t* node)
{
&#160;&#160; &#160;rbtree_node_t* brother = NULL;

&#160;&#160; &#160;while(node != tree->root && rbtree_is_black(node))
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;if (node == node->parent->left)
&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;brother = node->parent->right;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;if (rbtree_is_red(brother))
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(brother);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_red(node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_left_rotate(tree, node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;/* update brother after topologic change of the tree */
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;brother = node->parent->right;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}

&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;if (rbtree_is_black(brother->left) && rbtree_is_black(brother->right))
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_red(brother);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;/* go upward and keep on fixing color */
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;node = node->parent;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;else
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;if (rbtree_is_black(brother->right))
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(brother->left);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_red(brother);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_right_rotate(tree, brother);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;/* update brother after topologic change of the tree */
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;brother = node->parent->right;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_copy_color(brother, node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(brother->right);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_left_rotate(tree, node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;/* end the loop and ensure root is black */
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;node = tree->root;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;/* same as the "if" clause before with "left" and "right" exchanged */
&#160;&#160; &#160;&#160;&#160; &#160;else
&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;brother = node->parent->left;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;if (rbtree_is_red(brother))
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(brother);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_red(node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_left_rotate(tree, node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;brother = node->parent->left;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}

&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;if (rbtree_is_black(brother->left) && rbtree_is_black(brother->right))
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_red(brother);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;node = node->parent;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;else
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;if (rbtree_is_black(brother->left))
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(brother->right);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_red(brother);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_right_rotate(tree, brother);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;brother = node->parent->left;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_copy_color(brother, node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(brother->left);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;rbtree_left_rotate(tree, node->parent);
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;node = tree->root;
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;}

&#160;&#160; &#160;rbtree_black(node);
}

/* public methods */
void rbtree_insert_value(rbtree_t* tree, rbtree_node_t* node)
{
&#160;&#160; &#160;/* Using ** to know wether the new node will be a left kid */
&#160;&#160; &#160;/* or a right kid of its parent node. */
&#160;&#160; &#160;rbtree_node_t** tmp = &tree->root;
&#160;&#160; &#160;rbtree_node_t* parent;

&#160;&#160; &#160;while(*tmp != tree->sentinel)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;parent = *tmp;

&#160;&#160; &#160;&#160;&#160; &#160;/* update node_cnt */
&#160;&#160; &#160;&#160;&#160; &#160;(parent->node_cnt)++;

&#160;&#160; &#160;&#160;&#160; &#160;tmp = (node->key key) ? &parent->left : &parent->right;
&#160;&#160; &#160;}

&#160;&#160; &#160;/* The pointer knows wether the node should be on the left side */
&#160;&#160; &#160;/* or on the right one. */
&#160;&#160; &#160;*tmp = node;
&#160;&#160; &#160;node->parent = parent;
&#160;&#160; &#160;node->left = tree->sentinel;
&#160;&#160; &#160;node->right = tree->sentinel;
&#160;&#160; &#160;rbtree_red(node);
}

void rbtree_visit(rbtree_node_t* node)
{
&#160;&#160; &#160;/* visiting the current node */
}

void rbtree_insert(rbtree_t* tree, rbtree_node_t* node)
{
&#160;&#160; &#160;rbtree_node_t* sentinel = tree->sentinel;

&#160;&#160; &#160;/* if the tree is empty */
&#160;&#160; &#160;if (tree->root == sentinel)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;tree->root = node;
&#160;&#160; &#160;&#160;&#160; &#160;node->parent = sentinel;
&#160;&#160; &#160;&#160;&#160; &#160;node->left = sentinel;
&#160;&#160; &#160;&#160;&#160; &#160;node->right = sentinel;
&#160;&#160; &#160;&#160;&#160; &#160;rbtree_black(node);

&#160;&#160; &#160;&#160;&#160; &#160;return;
&#160;&#160; &#160;}

&#160;&#160; &#160;/* generally */
&#160;&#160; &#160;tree->insert(tree, node);
&#160;&#160; &#160;rbtree_insert_fixup(tree, node);
}

void rbtree_delete(rbtree_t* tree, rbtree_node_t* node)
{
&#160;&#160; &#160;rbtree_node_t* sentinel = tree->sentinel;
&#160;&#160; &#160;/* wether "node" is on the left side or the right one */
&#160;&#160; &#160;rbtree_node_t** ptr_to_node = NULL;
&#160;&#160; &#160;/* "cover" is the node which is going to cover "node" */
&#160;&#160; &#160;rbtree_node_t* cover = NULL;
&#160;&#160; &#160;/* wether we lossing a red node on the edge of the tree */
&#160;&#160; &#160;int loss_red = rbtree_is_red(node);
&#160;&#160; &#160;int is_root = (node == tree->root);

&#160;&#160; &#160;/* get "cover" & "loss_red"&#160; */
&#160;&#160; &#160;/* sentinel in "node"&#39;s kids */
&#160;&#160; &#160;if (node->left == sentinel)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;cover = node->right;
&#160;&#160; &#160;}
&#160;&#160; &#160;else if (node->right == sentinel)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;cover = node->left;
&#160;&#160; &#160;}
&#160;&#160; &#160;/* "node"&#39;s kids are both non-sentinel */
&#160;&#160; &#160;else
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;/* update "node" & "loss_red" & "is_root" & "cover" */
&#160;&#160; &#160;&#160;&#160; &#160;cover = rbtree_subtree_min(node->right, sentinel);
&#160;&#160; &#160;&#160;&#160; &#160;node->key = cover->key;
&#160;&#160; &#160;&#160;&#160; &#160;node->value = cover->value;
&#160;&#160; &#160;&#160;&#160; &#160;node = cover;
&#160;&#160; &#160;&#160;&#160; &#160;loss_red = rbtree_is_red(node);
&#160;&#160; &#160;&#160;&#160; &#160;is_root = 0;
&#160;&#160; &#160;&#160;&#160; &#160;/* move "cover"&#39;s kids */
&#160;&#160; &#160;&#160;&#160; &#160;/* "cover" can only be a left kid */
&#160;&#160; &#160;&#160;&#160; &#160;/* and can only have a right non-sentinel kid */
&#160;&#160; &#160;&#160;&#160; &#160;/* because of function "rbtree_subtree_min" */
&#160;&#160; &#160;&#160;&#160; &#160;cover = node->right;
&#160;&#160; &#160;}

&#160;&#160; &#160;if (is_root)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;/* update root */
&#160;&#160; &#160;&#160;&#160; &#160;tree->root = cover;
&#160;&#160; &#160;}
&#160;&#160; &#160;else
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;/* downward link */
&#160;&#160; &#160;&#160;&#160; &#160;if (node == node->parent->left)
&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;node->parent->left = cover;
&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;else
&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;node->parent->right = cover;
&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;}
&#160;&#160; &#160;/* upward link */
&#160;&#160; &#160;cover->parent = node->parent;
&#160;&#160; &#160;/* "cover" may be a sentinel */
&#160;&#160; &#160;if (cover != sentinel)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;/* set "cover" */
&#160;&#160; &#160;&#160;&#160; &#160;cover->left = node->left;
&#160;&#160; &#160;&#160;&#160; &#160;cover->right = node->right;
&#160;&#160; &#160;&#160;&#160; &#160;rbtree_copy_color(cover, node);
&#160;&#160; &#160;}

&#160;&#160; &#160;/* clear "node" since it&#39;s useless */
&#160;&#160; &#160;node->key = -1;
&#160;&#160; &#160;node->parent = NULL;
&#160;&#160; &#160;node->left = NULL;
&#160;&#160; &#160;node->right = NULL;
&#160;&#160; &#160;node->value = NULL;

&#160;&#160; &#160;/* update node_cnt */
&#160;&#160; &#160;rbtree_node_t* tmp = cover->parent;
&#160;&#160; &#160;while(tmp != sentinel)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;(tmp->node_cnt)--;
&#160;&#160; &#160;&#160;&#160; &#160;tmp = tmp->parent;
&#160;&#160; &#160;}

&#160;&#160; &#160;if (loss_red)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;return;
&#160;&#160; &#160;}

&#160;&#160; &#160;/* When lossing a black node on edge */
&#160;&#160; &#160;/* the fifth rule of red-black tree will be broke. */
&#160;&#160; &#160;/* So the tree need to be fixed. */
&#160;&#160; &#160;rbtree_delete_fixup(tree, cover);
}

/* find the node in the tree corresponding to the given key value */
rbtree_node_t* rbtree_find(rbtree_t* tree, rbtree_key_t key)
{
&#160;&#160; &#160;rbtree_node_t* tmp = tree->root;
&#160;&#160; &#160;/* next line is just fot test */
&#160;&#160; &#160;// int step_cnt = 0;

&#160;&#160; &#160;/* search the binary tree */
&#160;&#160; &#160;while(tmp != tree->sentinel)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;/* next line is just fot test */
&#160;&#160; &#160;&#160;&#160; &#160;// step_cnt++;
&#160;&#160; &#160;&#160;&#160; &#160;if(key == tmp->key)
&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;/* next line is just for test */
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;// printf("step count: %d, color: %s, ", step_cnt, rbtree_is_red(tmp) ? "red" : "black");
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;return tmp;
&#160;&#160; &#160;&#160;&#160; &#160;}

&#160;&#160; &#160;&#160;&#160; &#160;tmp = (key key) ? tmp->left : tmp->right;
&#160;&#160; &#160;}

&#160;&#160; &#160;return NULL;
}

/* find the node in the tree corresponding to the given order number */
rbtree_node_t* rbtree_index(rbtree_t* tree, int index)
{
&#160;&#160; &#160;if (index <0 || index >= rbtree_count(tree))
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;return NULL;
&#160;&#160; &#160;}

&#160;&#160; &#160;rbtree_node_t* tmp = tree->root;
&#160;&#160; &#160;int left_cnt = 0;
&#160;&#160; &#160;int sub_left_cnt;

&#160;&#160; &#160;while(tmp->node_cnt > 0)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;sub_left_cnt = tmp->left->node_cnt;
&#160;&#160; &#160;&#160;&#160; &#160;if (left_cnt + sub_left_cnt == index)
&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;return tmp;
&#160;&#160; &#160;&#160;&#160; &#160;}

&#160;&#160; &#160;&#160;&#160; &#160;if (left_cnt + sub_left_cnt right;
&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;&#160;&#160; &#160;else
&#160;&#160; &#160;&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;&#160;&#160; &#160;tmp = tmp->left;
&#160;&#160; &#160;&#160;&#160; &#160;}
&#160;&#160; &#160;}
}

/* get the height of the subtree */
int rbtree_height(rbtree_t* tree, rbtree_node_t* node)
{
&#160;&#160; &#160;if (node == tree->sentinel)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;return 0;
&#160;&#160; &#160;}

&#160;&#160; &#160;int left_height = rbtree_height(tree, node->left);
&#160;&#160; &#160;int right_height = rbtree_height(tree, node->right);
&#160;&#160; &#160;int sub_height = (left_height > right_height) ? left_height : right_height;
&#160;&#160; &#160;return sub_height+1;
}

/* get the count of nodes in the tree */
int rbtree_count(rbtree_t* tree)
{
&#160;&#160; &#160;return tree->root->node_cnt;
}

/* visit every node of the subtree whose root is given in order */
void rbtree_traversal(rbtree_t* tree, rbtree_node_t* node, rbtree_visit_p visit)
{
&#160;&#160; &#160;if (node != tree->sentinel)
&#160;&#160; &#160;{
&#160;&#160; &#160;&#160;&#160; &#160;rbtree_traversal(tree, node->left, visit);
&#160;&#160; &#160;&#160;&#160; &#160;visit(node);
&#160;&#160; &#160;&#160;&#160; &#160;rbtree_traversal(tree, node->right, visit);
&#160;&#160; &#160;}
}

还是做个压力测试。

test.c:

#include 
#include 
#include 
#include "rbtree.h"

int main(int argc, char const *argv[])
{
	double duration;
	double room;

	rbtree_t t = {};
	rbtree_node_t s = {};
	rbtree_init(&t, &s, rbtree_insert_value);

	const int cnt = 1<<20;
	const int max_len = 15;

#define TEST_VALUES {"apple", "banana", "cherry", "grape", "lemon", "mango", "pear", "pineapple", "strawberry", "watermelon"}

	/* for gcc */
	char* v[] = TEST_VALUES;
	/* for g++ */
	// char v[][max_len] = TEST_VALUES;

	/* Default stack size in Ubuntu Kylin 14.04 is 8MB. */
	/* It&#39;s not enough. So I use memory in heap which offers a lot larger room. */
	rbtree_node_t* n = (rbtree_node_t*)calloc(cnt, sizeof(rbtree_node_t));
	int i;

	long time1 = clock();

	for (i = 0; i key = %d\n", no, rbtree_index(&t, no)->key);

	long time2 = clock();
	room = 48.0*cnt/(1<<20);
	duration = (double)(time2 - time1) / CLOCKS_PER_SEC;
	printf("Inserting %d nodes costs %.2fMB and spends %f seconds.\n", cnt, room, duration);

	const int search_cnt = 1<<10;
	for( i = 0 ; i     上一个版本的压力测试结果:
Inserting 1048576 nodes costs 48.00MB and spends 0.425416 seconds.
Searching 1024 nodes among 1048576 spends 0.001140 seconds.
Hash 1024 times spends 0.000334 seconds.
Deleting 1024 nodes among 1048576 spends 0.000783 seconds.
扩展版本的压力测试结果:
Inserting 1048576 nodes costs 48.00MB and spends 0.467859 seconds.
Searching 1024 nodes among 1048576 spends 0.001188 seconds.
Indexing 1024 nodes among 1048576 spends 0.001484 seconds.
Hash 1024 times spends 0.000355 seconds.
Deleting 1024 nodes among 1048576 spends 0.001417 seconds.
The height of the tree is 28. Getting it spends 0.021669 seconds.
Traversal the tree spends 0.023913 seconds.
Count of nodes in the tree is 1047552.
比较一下可以发现:

1.插入结点略慢了一点,因为插入时多维护了一个node_cnt项。

2.按key查找结点速度没有变化。

3.哈希查找速度没有变化。

4.删除结点花的时间几乎是原来的两倍,因为每次删除后都要一路向上更新node_cnt,几乎相当于包含了一次按key查询。

5.按序号查询比按key查询略慢,因为每次进入右子树需要多做一次加法。

6.遍历花的时间与求树高相同,因为它们的实质都是遍历树,时间效率O(n)数量级,具体点为2n次结点访问,分别为结点入栈和出栈时。

别问我max、min、mid在哪,能按序号查询了这些还是问题吗?

版权声明:本文为博主原创文章,未经博主允许不得转载。

以上就介绍了nginx的数据结构3——扩展红黑树,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

推荐阅读
  •  在使用PHP多年之后,我对PHP的优势和劣势已经非常清楚,与后起之秀Golang相比,两者已经不在一个重量级。 PHP更像是70kg级别的选手,脚本语言,极速开发,部署方便,性能 ... [详细]
  • PHP Warning: Module ‘modulename’ already loaded in问题解决办法【PHP】
    后端开发|php教程PHP,Warning,Module,modulename,already,loaded后端开发-php教程出现标题这样的错误大概是:充值网站源码,虚拟机下运行 ... [详细]
  • Nginx简介Nginx(enginex)是一个高性能的HTTP和反向代理服务器,也是一个IMAPPOP3SMTP代理服务器。Nginx是由IgorSysoev为 ... [详细]
  • win10下载速度慢
    运维|windows运维win10,下载,速度慢运维-windows运维秒赞源码详细说明,vscode怎么跑项目,台电安装ubuntu,tomcat记录请求报文,sqlite的数据 ... [详细]
  • 在云服务器中搭建Jupyter Notebook环境
    目录前言二、JupyterNotebook搭建步骤1.云服务器准备2.安装Python及pip3.安装JupyterNotebook4.运行JupyterNoteboo ... [详细]
  • php 字符串分割和比较介绍
    后端开发|php教程字符串,php,介绍后端开发-php教程比较两个字符串是否相等,最常见的方法就是使用“”来判断,至于它和“”的区别,简单来说就是前者强调“Identical”类 ... [详细]
  • phpcms v9无法连接数据库怎么办
    CMS教程|PHPCMSphpcmsCMS教程-PHPCMSqq骂人源码,vscode搜索不到中文插件,ubuntu输入法下载,f14tomcat,sqliteknex,网页设计图 ... [详细]
  • php实现中文文件下载
    php教程|PHP源码php实现中文文件下载php教程-PHP源码php代码爱之谷2015源码,ubuntu16桌面,tomcat9解压缩半,python爬虫带页面,php批量删除 ... [详细]
  • “近年来最大计算机漏洞”被中国程序员发现!
    头条中国程序员,计算机漏洞头条(观察者网讯)据美联社12月11日报道,中国阿里云安全团队在Web服务器软件阿帕奇(Apache)下的开源日志组件Log4j内,发现一个漏洞Log4S ... [详细]
  • Docker基础和常用命令详解_docker
    这篇文章主要介绍了Docker基础和常用命令方法的相关资料, ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 解决php错误信息不显示在浏览器上的方法
    本文介绍了解决php错误信息不显示在浏览器上的方法。作者发现php中的各种错误信息并不显示在浏览器上,而是需要在日志文件中查看。为了解决这个问题,作者提供了一种解决方式:通过修改php.ini文件中的display_errors参数为On,并重启服务。这样就可以在浏览器上直接显示php错误信息了。 ... [详细]
  • LVS实现负载均衡的原理LVS负载均衡负载均衡集群是LoadBalance集群。是一种将网络上的访问流量分布于各个节点,以降低服务器压力,更好的向客户端 ... [详细]
  • 目录浏览漏洞与目录遍历漏洞的危害及修复方法
    本文讨论了目录浏览漏洞与目录遍历漏洞的危害,包括网站结构暴露、隐秘文件访问等。同时介绍了检测方法,如使用漏洞扫描器和搜索关键词。最后提供了针对常见中间件的修复方式,包括关闭目录浏览功能。对于保护网站安全具有一定的参考价值。 ... [详细]
author-avatar
辽宁琢一传媒
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有