一下是红黑树增删查,包含了一个完整的demo。
1. 由于插入操作比较简单,就不讲了直接上代码:
/**
* @brief Left rotate.
* step:
* 1. right child becomes the parent node, if current node`s parrent is null,
* the right node becomes root node.
* 2. right child`s left child becomes current node`s right node.
* 3. current node becomes right child`s left child.
* current node = previous parent node.
* eg:left node a.
* a c
* / \ left rotate / \
* b c ===============>> a g
* / \ / \ / \
* d e f g b f
* / \
* d e
* @return rd_node_t*
*
* @anchor cj
*/
void left_rotate(rd_node_t **root, rd_node_t *cur_node)
{
rd_node_t *right_node = cur_node->right;
/* step 1 */
right_node->parent = cur_node->parent;
if (!cur_node->parent) {
/* current node is root. */
*root = right_node;
} else if (cur_node == cur_node->parent->left) {
/* if current node is in left tree. */
cur_node->parent->left = right_node;
} else {
/* current node is right tree. */
cur_node->parent->right = right_node;
}
/* step 2 */
cur_node->right = right_node->left;
if (right_node->left) {
right_node->left->parent = cur_node;
}
/* step 3 */
right_node->left = cur_node;
cur_node->parent = right_node;
}
/**
* @brief right rotate.
* step:
* 1. left child becomes the parent node.if current node`s parrent is null,
* the left node becomes root node.
* 2. left child`s right child becomes current node`s right node.
* 3. current node becomes right child`s left child.
* current node = previous parent node.
* eg:right node a.
* a b
* / \ right rotate / \
* b c ===============>> d a
* / \ / \ / \
* d e f g e c
* / \
* f g
* @return rd_node_t*
*
* @anchor cj
*/
void right_rotate(rd_node_t **root, rd_node_t *cur_node)
{
rd_node_t *left_node = cur_node->left;
struct test_info *info = NULL;
/* step 1 */
left_node->parent = cur_node->parent;
if (!cur_node->parent) {
/* root node. */
*root = left_node;
} else if (cur_node == cur_node->parent->left) {
/* current node is left tree. */
cur_node->parent->left = left_node;
} else {
/* current node is right tree. */
cur_node->parent->right = left_node;
}
/* step 2. */
cur_node->left = left_node->right;
if (left_node->right) {
left_node->right->parent = cur_node;
}
/* step 3. */
cur_node->parent = left_node;
left_node->right = cur_node;
}
/**
* @brief 红黑树性质
* 1. 每个节点要么是红色,要么是黑色。
* 2. 根节点是黑色。
* 3. 每个叶子节点(NIL节点)是黑色。----其实就是空指针叶子
* 4. 如果一个节点是红色,那么它的两个子节点都是黑色。 ----- 插入一个节点要默认成红色原因,NIL节点是黑色的。
* 5. 对于每个节点,从该节点到其所有后代叶子节点的简单路径上,均包含相同数目的黑色节点。
*
*/
/**
* @brief fix red black tree
* step:
* 插入修正:
* 当向红黑树中插入一个节点时,会破坏红黑树的平衡性质。为了修正这种破坏,需要进行以下操作:
*
* a) 如果插入的是根节点,直接将其染成黑色。
* b) 如果插入的节点的父节点是黑色的,不需要做任何修正。
* c) 如果插入的节点的父节点是红色的,需要进行下面的修正操作:
* case 1. 当前节点的父节点是红色,且当前节点的祖父节点的另一个子节点(叔叔节点)也是红色
* (01)将“父节点”设为黑色。(02)将“叔叔节点”设为黑色。(03)将“祖父节点”设为“红色” (04)将“祖节点”设为“当前节点”(红色节点);即,之后继续对“当前节点”进行操作.
* case 2. 父亲节点是左子树,当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的右孩子
* (01)将“父节点”作为“新的当前节点” (02)以“新的当前节点”为支点进行左旋。
* case 3. 父亲节点是左子树,当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的左孩子
* (01)将“父节点”设为“黑色 (02)将“祖父节点”设为“红色”。(03)以“祖父节点”为支点进行右旋。
* case 4. 父亲节点是右子树,叔叔节点为黑色或者不存在,当前节点是父节点的左子节点,将设置当前节点为父节点,并以更新后的节点为支点进行右旋。
* case 5. 父亲节点是右子树,叔叔节点为黑色或者不存在,当前节点是父节点的右子节点,将当前节点的父节点染黑,祖父节点染红,设置当前节点为祖父节点,并以更新后的当前节点为支点进行左旋。
* @author cj.2023-12-28
*
* @return NULL
*/
void rd_fix_insert(rd_node_t **root, rd_node_t *cur_node)
{
rd_node_t *uncle;
/* 当前是根节点,直接染黑;如果父节点是红色,需要调整;由于根节点始终是黑色的,所以如果父节点是根节点时就不需要遍历调整了 */
while (cur_node && cur_node->parent && cur_node->parent->parent && (cur_node->parent->color == RD_RED)) {
if (cur_node->parent->parent->left == cur_node->parent) { /* 父节点是左子树,叔叔节点是右子树 */
uncle = cur_node->parent->parent->right;
} else { /* 父节点是右子树,叔叔节点是左子树 */
uncle = cur_node->parent->parent->left;
}
/* 如果叔叔节点存在,则查看叔叔节点是否为红色,如果为红色,则叔叔节点和父亲节点染黑,祖父节点染红,并将当前节点置为祖父节点继续判断 */
if (uncle && uncle->color == RD_RED) {
uncle->color = RD_BLACK;
cur_node->parent->color = RD_BLACK;
cur_node->parent->parent->color = RD_RED;
cur_node = cur_node->parent->parent;
continue;
} else {
/* 如果父亲节点是左子树 */
if (cur_node->parent->parent->left == cur_node->parent) {
/* 如果叔叔节点不存在或者是黑色,且插入节点为左子节点,则将父节点染黑,祖父节点染红,并以祖父节点为支点进行右旋 */
if (cur_node->parent->left == cur_node) {
cur_node->parent->color = RD_BLACK;
cur_node->parent->parent->color = RD_RED;
cur_node = cur_node->parent->parent;
right_rotate(root, cur_node);
} else {
/* 如果插入节点是右子树,并以父节作为当前节点,以父节点为支点左旋 */
cur_node = cur_node->parent;
left_rotate(root, cur_node);
}
} else { /* 如果父亲节点是右子树 */
/* 如果叔叔节点不存在或者是黑色,且插入节点为右子节点,则将父节点染黑,祖父节点染红,并以祖父节点为支点进行右旋 */
if (cur_node->parent->right == cur_node) {
cur_node->parent->color = RD_BLACK;
cur_node->parent->parent->color = RD_RED;
cur_node = cur_node->parent->parent;
left_rotate(root, cur_node);
} else {
/* 如果插入节点是左子树,并以父节作为当前节点,以父节点为支点右旋 */
cur_node = cur_node->parent;
right_rotate(root, cur_node);
}
}
}
}
(*root)->color = RD_BLACK;
}
/**
* @brief insert rd node.
*
*
* @author cj.2023-12-28
*
* @return NULL
*
*/
void rd_insert_node(rd_node_t **root, rd_node_t *new_node)
{
rd_node_t *cur_node = *root;
if (!(*root)) {
*root = new_node;
return;
}
if (!new_node) {
return;
}
while (cur_node) {
if (cur_node->index < new_node->index) {
if (cur_node->right) {
cur_node = cur_node->right;
} else {
cur_node->right = new_node;
new_node->parent = cur_node;
rd_fix_insert(root, new_node);
break;
}
} else {
if (cur_node->left) {
cur_node = cur_node->left;
} else {
cur_node->left = new_node;
new_node->parent = cur_node;
rd_fix_insert(root, new_node);
break;
}
}
}
}
2. 第二部分是查找一个节点
rd_node_t *find_rd_node(rd_node_t *root, int index)
{
rd_node_t *cur_node = root;
while (cur_node) {
if (index > cur_node->index) {
cur_node = cur_node->right;
} else if (index < cur_node->index) {
cur_node = cur_node->left;
} else {
return cur_node;
}
}
return NULL;
}
3. 删除比较复杂,建议新手先阅读一下上一篇删除单个节点情况
/**
* @brief delete a rd node.
* 1. 删掉一个单独的红色节点,该红节点无孩子,直接删除即可。
* 2. 被删节点node为黑色且无子节点
* case 1: 兄弟节点sibling有一个与sibling方向一致的红色子节点【方向一致是指节点与子节点都是左子节点或者都是右子节点】,
* 如果删除节点node是左节点,兄弟节点为父节点颜色, 父节点黑色,兄弟节点孩子黑色,以父节点为支点左旋,否则右旋。
* case 2:兄弟节点sibling为黑色,且有一个与sibling方向相反的红色子节点,删除node,将sibling与sibling的son旋转,然后父节点和兄弟孩子的颜色对调,
* 父节点置为黑色,转换成【case 1】
* case 3:兄弟节点sibling为黑色且无红色子节点,直接删除node,并进行以下操作:
* 1). 若父节点为红色,则父亲节点颜色和兄弟节点颜色对调。结束。
* 2). 若父节点为黑色,则将node置为father节点继续向上判断,然后继续判断直到到达根为止。
* case 4:如果兄弟是红色,则以父节点为支点进行旋转,从而变成case 1、2、3的一种情况
* 3. 被删节点是红色的且只有一个子节点,这种是异常情况。---抛出异常
* 4. 被删节点只有一个子节点且被删节点为黑色,直接用子节点替代被删节点,然后染黑即可。
* 5. 被删节点有两个子节点
* node
* / \
* left right
* / \ / \
* 前驱节点 后继节点
*
* 注:前驱节点:左子树上最大值,后继节点右子树上的最小值。
* 使用前驱节点或者后继节点的值替代node,不需要改变颜色,然后删掉前驱节点或者后继节点。
* (1)如果前驱或者后继是红色,且无孩子退化成【组合1】,黑色无孩子退化成【组合2】
* (2)如果前驱或者后继是红色,且有一个孩子,则退化成【组合1】或者【组合3】,否则黑色有一个孩子退化成【组合4】
* @author cj.2023-1-2
*
* @return
* if exist the node, return aim rd node.
* else return NULL;
*
*/
/* 查找前驱节点 */
static rd_node_t *find_precursor(rd_node_t *cur_node)
{
while (cur_node) {
if (cur_node->right) {
cur_node = cur_node->right;
continue;
}
break;
}
return cur_node;
}
/* 查找后继节点 */
static rd_node_t *find_successor(rd_node_t *cur_node)
{
while (cur_node) {
if (cur_node->left) {
cur_node = cur_node->left;
continue;
}
break;
}
return cur_node;
}
void dump_rd_tree(rd_node_t *root)
{
if (!root) {
return;
}
printf("val = %d color=%d", root->index, root->color);
if (root->parent) {
printf("parent index=%d\n", root->parent->index);
} else {
printf("\n");
}
dump_rd_tree(root->left);
dump_rd_tree(root->right);
}
/**
* @brief delete a black node without child.
* case 1:兄弟为黑色,且有红孩子:
* (1)如果兄弟节点和其子节点方向一致,则子节点=兄弟节点颜色,兄弟节点=父节点颜色,父节点=被删节点颜色,然后旋转(删除左孩子就左旋,否则右旋)
* (2)如果兄弟节点和其子节点方向一致,则子节点=父节点颜色,父节点=被删节点颜色,然后以兄弟为支点旋转(删除左孩子右旋,否则左旋),转为(1)
*
* case 2: 兄弟为黑色,此时兄弟一定没有孩子
* 父亲为红色:则兄弟改为红色,父亲改成黑色。结束
* 父亲为黑色: 将兄弟染红,以父亲为节点继续向上遍历,期望遇到其他情况化解少一个黑色节点的情况。或者一直遇不到其他情况,每层子树少一个黑色节点,
* 这样直到根节点时让根的另一个子树也少一个黑色节点,根两边平衡,结束。
*
* case 3: 兄弟为红色,则一定有两个黑色孩子,且父亲必定是黑色,否则不满足性质5.
* 将父亲节点染红、兄弟节点染黑,然后以父亲节点旋转(删掉节点是左子树就左旋,否则右旋),转换成其他的case。
*
* @param root : rd tree root noder.
* @param del_node : The rd node to be delete.
* @return balance ok: 0 ocurr error: -1
*/
char rd_tree_balance_single_black_node(rd_node_t **root, rd_node_t *del_node)
{
rd_node_t *p_del = del_node;
rd_node_t *sibling = NULL;
rd_node_t *sibling_child = NULL;
u8 sibling_direct, sibling_child_direct;
while (p_del && !rd_is_root(p_del, *root)) {
if (p_del->parent->left == p_del) {
sibling_direct = RD_CHILD_RIGHT;
} else {
sibling_direct = RD_CHILD_LEFT;
}
sibling = rd_child(p_del->parent, sibling_direct);
if (sibling) {
/* case 1 */
if ((sibling->left && (sibling->left->color == RD_RED)) ||
(sibling->right && (sibling->right->color == RD_RED))) { /* sibling have RED child */
if ((sibling_child = rd_child(sibling, sibling_direct))
&& (sibling_child->color == RD_RED)) {
/* The direction of child is consistent with that of the sibling. */
sibling_child->color = RD_BLACK;
sibling->color = sibling->parent->color;
sibling->parent->color = RD_BLACK;
if (sibling_direct == RD_CHILD_LEFT) {
right_rotate(root, sibling->parent);
} else {
left_rotate(root, sibling->parent);
}
} else { /* The direction of child is opposite to that of the sibling. */
sibling_child_direct = rd_opposite_direct(sibling_direct);
sibling_child = rd_child(sibling, sibling_child_direct);
sibling_child->color = sibling->parent->color;
sibling->parent->color = RD_BLACK;
if (sibling_direct == RD_CHILD_LEFT) {
left_rotate(root, sibling);
right_rotate(root, sibling_child->parent); /* notification: now sibling_child is sibling */
} else {
right_rotate(root, sibling);
left_rotate(root, sibling_child->parent); /* notification: now sibling_child is sibling */
}
}
break;
} else {
/* case 2: sibling is black, father is black or red. */
if (rd_color_is_black(sibling)) {
if (rd_color_is_black(sibling->parent)) {
sibling->color = RD_RED;
p_del = sibling->parent;
continue;
} else {
sibling->color = RD_RED;
sibling->parent->color = RD_BLACK;
break;
}
} else if (rd_color_is_black(sibling->parent) && !rd_color_is_black(sibling)) {
/* case 3: father black and sibling red. */
sibling->color = RD_BLACK;
sibling->parent->color = RD_RED;
if (sibling_direct == RD_CHILD_LEFT) {
right_rotate(root, sibling->parent);
} else {
left_rotate(root, sibling->parent);
}
} else {
dump_rd_tree(*root);
rd_debug(RD_DEBUG_LEVEL_ERR, rd_debug_info[RD_DEBUG_PROPERTY_5_ERR]);
return RET_ERR;
}
}
} else {
dump_rd_tree(*root);
rd_debug(RD_DEBUG_LEVEL_ERR, rd_debug_info[RD_DEBUG_PROPERTY_5_ERR]);
return RET_ERR;
}
}
return RET_OK;
}
/**
* @brief swap rd node position.
* @param root : rd tree root noder.
* @param s1 : swap node.
* @param s2 : swap node 2.
* @return balance ok: 0 ocurr error: -1
*
*/
char swap_node(rd_node_t **root, rd_node_t *s1, rd_node_t *s2)
{
rd_node_t *d_node = s1, *s_node= s2;
rd_node_t tmp = {0};
rd_node_t *rd_tmp_ptr;
u8 direct = RD_CHILD_LEFT;
if (!d_node || !s_node) {
rd_debug(RD_DEBUG_LEVEL_ERR, "src node or dest node is null.");
return RET_ERR;
}
restart:
if (s_node->left == d_node) {
direct = RD_CHILD_LEFT;
} else if (s_node->right == d_node) {
direct = RD_CHILD_RIGHT;
} else if (s_node->parent == d_node) {
rd_tmp_ptr = d_node;
d_node = s_node;
s_node = rd_tmp_ptr;
goto restart;
} else {
direct = RD_CHILD_NONE;
}
memcpy(&tmp, s_node, sizeof(rd_node_t));
/* swap color */
s_node->color = d_node->color;
d_node->color = tmp.color;
/* s_node swap d_node */
s_node->left = d_node->left;
if (d_node->left) {
d_node->left->parent = s_node;
}
s_node->right = d_node->right;
if (d_node->right) {
d_node->right->parent = s_node;
}
/* d_node swap s_node */
rd_tmp_ptr = d_node->parent;
d_node->parent = s_node->parent;
if (s_node->parent) {
if (s_node->parent->left == s_node) {
s_node->parent->left = d_node;
} else {
s_node->parent->right = d_node;
}
}
if (direct == RD_CHILD_NONE) {
s_node->parent = rd_tmp_ptr;
if (s_node->parent) {
if (s_node->parent->left == d_node) {
s_node->parent->left = s_node;
} else {
s_node->parent->right = s_node;
}
}
d_node->left = tmp.left;
if (d_node->left) {
d_node->left->parent = d_node;
}
d_node->right = tmp.right;
if (d_node->right) {
d_node->right->parent = d_node;
}
} else {
s_node->parent = d_node;
*rd_child_ptr(d_node, direct) = s_node;
direct = rd_opposite_direct(direct);
*rd_child_ptr(d_node, direct) = rd_child(&tmp, direct);
if (rd_child(d_node, direct)) {
(*rd_child_ptr(d_node, direct))->parent = d_node;
}
}
if (!s_node->parent) {
*root = s_node;
}
if (!d_node->parent) {
*root = d_node;
}
return RET_OK;
}
char rd_delete_node_balance_tree(rd_node_t **root, rd_node_t *del_node)
{
rd_node_t *p_del = del_node;
rd_node_t *rd_tmp;
if (!p_del) {
rd_debug(RD_DEBUG_LEVEL_ERR, "The delete node is null.");
return RET_ERR;
}
// dump_rd_tree(*root);
while (p_del) {
if (rd_empty_child(p_del)) { /* the node don`t have child. */
if (rd_color_is_black(p_del)) { /* black need balance, red just delete. */
return rd_tree_balance_single_black_node(root, p_del);
}
break;
} else if (rd_two_child(p_del)) { /* the node have two children. */
rd_tmp = find_precursor(p_del->left);
if (swap_node(root, rd_tmp, p_del) == RET_ERR) {
rd_debug(RD_DEBUG_LEVEL_ERR, "presursor swap delete node failed!");
return RET_ERR;
}
continue;
} else { /* the node just have a child. */
/* just have a child, must be black node, and it`s child is red. */
if (rd_color_is_black(p_del)) {
if (!(rd_tmp = rd_child(p_del, RD_CHILD_LEFT))) {
rd_tmp = rd_child(p_del, RD_CHILD_RIGHT);
}
if (swap_node(root, rd_tmp, p_del) == RET_ERR) {
rd_debug(RD_DEBUG_LEVEL_ERR, "presursor swap delete node failed!");
return RET_ERR;
}
continue;
} else {
dump_rd_tree(*root);
rd_debug(RD_DEBUG_LEVEL_ERR, rd_debug_info[RD_DEBUG_PROPERTY_5_ERR]);
return RET_ERR;
}
}
}
return RET_OK;
}
char rd_remove_node(rd_node_t *del_node)
{
if (!rd_empty_child(del_node)) {
rd_debug(RD_DEBUG_LEVEL_ERR, "delete node has child, delete failed!");
return RET_ERR;
}
if (del_node) {
if (del_node->parent) {
if (del_node->parent->left == del_node) {
del_node->parent->left = NULL;
} else {
del_node->parent->right = NULL;
}
}
del_node->left = NULL;
del_node->right = NULL;
del_node->parent = NULL;
}
}
char rd_delete_node(rd_node_t **root, rd_node_t *del_node)
{
if (!del_node) {
rd_debug(RD_DEBUG_LEVEL_WARNING, "delete rd node is null!");
return RET_ERR;
}
if (rd_delete_node_balance_tree(root, del_node)) {
rd_debug(RD_DEBUG_LEVEL_ERR, "balance rd tree before delete a node error!");
return RET_ERR;
}
return rd_remove_node(del_node);
}
4. rd_tree.h 和 common.h
//rd_tree.h
#ifndef _RD_TREE_H
#define _RD_TREE_H
#include "common.h"
/********************************************************************************************************
* enum
********************************************************************************************************/
enum {
RD_CHILD_LEFT = 0,
RD_CHILD_RIGHT,
RD_CHILD_NONE
};
enum {
RD_DEBUG_PROPERTY_1_ERR = 0,
RD_DEBUG_PROPERTY_2_ERR,
RD_DEBUG_PROPERTY_3_ERR,
RD_DEBUG_PROPERTY_4_ERR,
RD_DEBUG_PROPERTY_5_ERR
};
enum {
RD_DEBUG_LEVEL_PRINT = 0,
RD_DEBUG_LEVEL_INFO,
RD_DEBUG_LEVEL_DEBUG,
RD_DEBUG_LEVEL_WARNING,
RD_DEBUG_LEVEL_ERR
};
/********************************************************************************************************
* struct
********************************************************************************************************/
typedef enum {
RD_RED = 0,
RD_BLACK,
} rd_color;
typedef struct rd_node {
int color;
int index;
struct rd_node *left;
struct rd_node *right;
struct rd_node *parent;
} rd_node_t;
/********************************************************************************************************
* define
********************************************************************************************************/
#define rd_empty_child(node) (!node->left && !node->right) /* 没有子节点 */
#define rd_two_child(node) (node->left && node->right)
#define rd_color_is_black(node) (node->color == RD_BLACK)
#define rd_child(ptr, child) (((child) == RD_CHILD_LEFT) ? ((ptr)->left) : ((ptr)->right)) /* 根据值获取子节点 */
#define rd_is_root(ptr, root) ((ptr) == (root))
#define rd_opposite_direct(direct) ((direct == RD_CHILD_LEFT)?RD_CHILD_RIGHT:RD_CHILD_LEFT)
#define debug_level_set RD_DEBUG_LEVEL_DEBUG
#define rd_debug(debug_level, ...) \
{ \
if (debug_level >= debug_level_set) { \
printf("[RD_DBG][%25s][%4d]:", __FUNCTION__, __LINE__); \
printf(__VA_ARGS__); \
printf("\n"); \
} \
}
static inline rd_node_t **rd_child_ptr(rd_node_t *ptr, u8 direct)
{
if (direct == RD_CHILD_LEFT) {
return &(ptr->left);
} else {
return &(ptr->right);
}
}
/********************************************************************************************************
* declare
********************************************************************************************************/
rd_node_t *create_rd_node();
void left_rotate(rd_node_t **root, rd_node_t *cur_node);
void right_rotate(rd_node_t **root, rd_node_t *cur_node);
void rd_fix_insert(rd_node_t **root, rd_node_t *cur_node);
void rd_insert_node(rd_node_t **root, rd_node_t *new_node);
rd_node_t *find_rd_node(rd_node_t *root, int index);
char rd_tree_balance_single_black_node(rd_node_t **root, rd_node_t *del_node);
char swap_node(rd_node_t **root, rd_node_t *s1, rd_node_t *s2);
char rd_remove_node(rd_node_t *del_node);
char rd_delete_node(rd_node_t **root, rd_node_t *del_node);
void dump_rd_tree(rd_node_t *root);
#endif
//common.h
#ifndef _COMMON_H
#define _COMMON_H
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long u64;
typedef unsigned long u64_ptr_t;
#define RET_ERR (-1)
#define RET_OK (0)
#define PARAMTER_ERR (-2)
#endif
5. 一个小demo,大致的思路就是使用双向链表和红黑树插入大量的数据,然后分别对红黑树和双向链表进行查找,对比两者的性能,另外就是使用红黑树删除一些节点,查看结果是否与预期相符。最后释放内存。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "info.h"
struct stack mystack = {0};
dlist_head_t rand_info_head;
/**
* @brief tree pre trave
* recursion trave binary tree.
*
* @return NULL
*
* @anchor cj
*/
void pre_trave_recursion(rd_node_t *rd)
{
struct test_info *info = NULL;
if (!rd) {
return;
}
info = container_of(rd, struct test_info, rd);
printf("<%s %d> info=%c index=%d\n", __FUNCTION__, __LINE__, info->info, rd->index);
pre_trave_recursion(rd->left);
pre_trave_recursion(rd->right);
}
/**
* @brief tree middle trave
* recursion trave binary tree.
*
* @return NULL
*
* @anchor cj
*/
void mid_trave_recursion(rd_node_t *rd)
{
struct test_info *info = NULL;
if (!rd) {
return;
}
mid_trave_recursion(rd->left);
info = container_of(rd, struct test_info, rd);
printf("<%s %d> info=%c index=%d\n", __FUNCTION__, __LINE__, info->info, rd->index);
mid_trave_recursion(rd->right);
}
/**
* @brief tree post trave
* recursion trave binary tree.
*
* @return NULL
*
* @anchor cj
*/
void post_trave_recursion(rd_node_t *rd)
{
struct test_info *info = NULL;
if (!rd) {
return;
}
post_trave_recursion(rd->left);
post_trave_recursion(rd->right);
info = container_of(rd, struct test_info, rd);
printf("<%s %d> info=%c index=%d\n", __FUNCTION__, __LINE__, info->info, rd->index);
}
/**
* @brief 先序遍历
*
* @param t
*/
void pre_trave(rd_node_t *rd)
{
rd_node_t *node = NULL;
struct test_info *info = NULL;
if (rd == NULL) {
return;
}
printf("先序遍历...\n");
mystack.stack_ptr = -1;
push_entry(&mystack, (long unsigned int)rd);
while(1) {
node = (rd_node_t *)pop_entry(&mystack);
if (node) {
info = container_of(node, struct test_info, rd);
printf("<%s %d> info=%c index=%d\n", __FUNCTION__, __LINE__, info->info, info->rd.index);
if (node->right) {
if (push_entry(&mystack, (long unsigned int)node->right)) {
break;
}
}
if (node->left) {
if (push_entry(&mystack, (long unsigned int)node->left)) {
break;
}
}
continue;
}
break;
}
}
static struct test_info *create_info_node(char c)
{
struct test_info *info = (struct test_info *)malloc(sizeof(struct test_info));
memset(info, 0, sizeof(struct test_info));
struct test_info *test = NULL;
info->info = c;
// test = container_of(&info->rd, struct test_info, rd);
// printf("test->info=%c\n", test->info);
return info;
}
static void show_list_info(dlist_t *head, rd_node_t *root)
{
struct test_info *info = NULL;
int count = 0, list_num = 0, all_count = 0;
foreach_dlist(info, head, list) {
count = test_find_rd_node(root, info->rd.index);
all_count += count;
list_num++;
printf("<%s %d> info=%c count=%d\n", __FUNCTION__, __LINE__, info->info, count);
}
if (list_num) {
printf("show_list_info: mean find times %f\n", ((float)all_count)/list_num);
}
}
static int64 get_current_u_time() {
struct timespec time;
int64 elapsed_us = 0;
clock_gettime(CLOCK_MONOTONIC, &time);
elapsed_us = time.tv_sec * 1000000LL + time.tv_nsec / 1000LL;
return elapsed_us;
}
/**
* @brief build a tree for test red balck tree.
* I defined a struct test_info, it include dlist and rd tree so that I can
* view all info list throught dlist or rd tree. But my main aim is to
* test rd tree.
* @return NULL
*
* @anchor cj
*
*
*/
static void build_rd_tree(rd_node_t **root, dlist_head_t *info_list_head)
{
struct test_info *info = NULL;
int i, random_num, rand_list_sz = 0, rand_list_max_sz = 1000;
char c;
unsigned int rd_create_num = 200000;
unsigned int rd_num_range = rd_create_num + 100000;
struct test_info *info_random;
int64 start, end;
init_dlist(&rand_info_head.head);
start = get_current_u_time();
srand(time(NULL));
for (i = 0; i < rd_create_num; i++) {
random_num = rand() % rd_num_range;
/* 防止index重复 */
while(find_rd_node(*root, random_num)) {
random_num = rand() % rd_num_range;
}
// printf("random_num=%d\n", random_num);
c = 'a' + random_num % 52;
info = create_info_node(c);
list_add(&info_list_head->head, &info->list);
info->rd.index = random_num;
#if 1
rd_insert_node(root, &info->rd);
#endif
#if 1 //test rd cabability
if (rand_list_sz < rand_list_max_sz) {
if((random_num % 2) == 0) {
rand_list_sz++;
info_random = create_info_node(c);
info_random->rd.index = random_num;
// printf("info_random: rd->index=%d\n", info_random->rd.index);
list_add(&rand_info_head.head, &info_random->list);
}
}
#endif
}
end = get_current_u_time();
printf("build_rd_tree: time=%ld(us)\n", (end - start));
}
static void free_info_list(dlist_head_t *info_list_head)
{
struct test_info *info = NULL;
if (!info_list_head) {
return;
}
foreach_dlist(info, (&info_list_head->head), list) {
free(info);
}
}
static void delete_random_rd_node_by_dlist(rd_node_t **root)
{
struct test_info *info = NULL;
rd_node_t *del_node = NULL;
if (!root || !(*root)) {
return;
}
printf("[%s %d]\n", __FUNCTION__, __LINE__);
foreach_dlist(info, (&rand_info_head.head), list) {
// printf("delete:info=%c rd->index=%d\n", info->info, info->rd.index);
del_node = find_rd_node(*root, info->rd.index);
if(rd_delete_node(root, del_node)) {
rd_debug(RD_DEBUG_LEVEL_ERR, "rm rd node failed!");
break;
}
}
}
static void test_random_search_val(dlist_head_t *info_list_head, rd_node_t **root)
{
struct test_info *info = NULL, *info_search = NULL;
dlist_t *info_d_list = 0;
int search_count = 0;
int num_dlist = 0;
int64 start, end;
if (!info_list_head) {
return;
}
/* 测试双向链表的平均搜索次数和耗时 */
start = get_current_u_time();
foreach_dlist(info, (&rand_info_head.head), list) {
num_dlist++;
foreach_dlist(info_search, (&info_list_head->head), list) {
search_count++;
if (info_search->rd.index == info->rd.index) {
break;
}
}
}
end = get_current_u_time();
printf("dlist search mean=%f take time=%ld(us)\n", ((float)search_count)/num_dlist, (end - start));
#if 1
search_count = 0;
/* 测试红黑树的平均搜索次数和耗时 */
start = get_current_u_time();
foreach_dlist(info, (&rand_info_head.head), list) {
num_dlist++;
search_count += test_find_rd_node(*root, info->rd.index);
}
end = get_current_u_time();
printf("rd tree search mean=%f take time=%ld(us)\n", ((float)search_count)/num_dlist, (end - start));
#endif
}
int main(int argc, char **argv)
{
rd_node_t *root = NULL;
dlist_head_t info_list_header;
// struct test_info *p_info = NULL;
init_dlist(&info_list_header.head);
build_rd_tree(&root, &info_list_header);
// show_list_info(&info_list_header.head, root);
//test rd_tree search cabablity.
test_random_search_val(&info_list_header, &root);
// dump_rd_tree(root);
delete_random_rd_node_by_dlist(&root);
// dump_rd_tree(root);
free_info_list(&info_list_header);
}
总体来说红黑树的构建和删除比较耗时,其效率远远低于链表,而搜索效率远远高于链表,尤其是数据量越大时优势越明显,当数据量达到千万级别时,红黑树由于其稳定的搜索性能带来的好处远大于链表。而数据量只有几十几百个差别并不大。即几十上百个数据、查询不频繁或者遍历时用链表,数据量适中且查询频繁可以考虑使用hash表,大数据级别用红黑树和hash表。