NGINX源码分析之哈希表和红黑树

上篇文章我们对nginx的内存池结构、数组链表、队列进行了一次分析。这次主要对nginx的红黑树和哈希表的源码做一下分析。

首先看看哈希表的结构

最重要的两个结构体是:

typedef struct {
    void             *value;//存储value的首指针
    u_short           len;//存储key的长度
    u_char            name[1];//存储着key的首指针
} ngx_hash_elt_t;


typedef struct {
    ngx_hash_elt_t  **buckets;
//二维指针,一维指向某个key的ngx_hash_elt_t*的内存,二维直接指向存储区域的内存
    ngx_uint_t        size;
} ngx_hash_t;

首先先明白一点,nginx的哈希表内存是提前分配好的(也是本人觉得最为垃圾的设计),也就是说如果哈希表已经初始化好并创建,我们就没办法中途随心所欲的往表里面插入自己想要的字段,这也和之前内存池的设定(分配后无用内存无法被人为回收再利用)有关系。所以哈希的初始化函数很长,但是实际的做法就是用户用ngx_hash_init送入键值数组(入参names),然后函数根据这个数组提前计算好每个哈希key桶里面的元素有多少个,某个key对应n个元素的value总共需要的内存块有多长,然后把元素通过已经计算好的hash规则把键值逐个覆盖到这片内存上面去。find查找键值则根据偏移量找到buckets[key]对应的多个键值内存,再逐个遍历过去。相应的代码段为:

//这段代码的作用是计算出需要多少个哈希桶,使得每个键对应的value内存不会超过bucket_size(最大内存) 
for (size = start; size <= hinit->max_size; size++) {

        ngx_memzero(test, size * sizeof(u_short));

        for (n = 0; n < nelts; n++) {
            if (names[n].key.data == NULL) {
                continue;
            }

            key = names[n].key_hash % size;
            //增加key处存储区域value的一次大小
            test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));

#if 0
            ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                          "%ui: %ui %ui \"%V\"",
                          size, key, test[key], &names[n].key);
#endif
            //如果超过就放弃这个size作为hash规则
            if (test[key] > (u_short) bucket_size) {
                goto next;
            }
        }

        goto found;

    next:

        continue;
    }
//源码338行:根据已经做好的规则计算好每个key的value的长度(多个就叠加),总大小存储在test[key]底下。
for (n = 0; n < nelts; n++) {
        if (names[n].key.data == NULL) {
            continue;
        }

        key = names[n].key_hash % size;
        test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
    }
/*源码386行:elts分配好内存大小,然后把每个buckets[i]的指针指向ngx_hash_elt_t *指针指向的
  内存存储区域(每个i其实就对应一个hashKey)
*/
    elts = ngx_align_ptr(elts, ngx_cacheline_size);
    for (i = 0; i < size; i++) {
        if (test[i] == sizeof(void *)) {
            continue;
        }

        buckets[i] = (ngx_hash_elt_t *) elts;
        elts += test[i];
    }
    //把数组的实值全部实值覆盖上去(注意到names是数组入参的指针头)
    for (n = 0; n < nelts; n++) {
        if (names[n].key.data == NULL) {
            continue;
        }

        key = names[n].key_hash % size;
        elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]);

        elt->value = names[n].value;
        elt->len = (u_short) names[n].key.len;

        ngx_strlow(elt->name, names[n].key.data, names[n].key.len);

        test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
    }

    //每个key最后一块内存的value都用NULL标记,表示完结
    for (i = 0; i < size; i++) {
        if (buckets[i] == NULL) {
            continue;
        }

        elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]);

        elt->value = NULL;
    }

哈希查找则是根据Bucket【key】开始的内存空间,按偏移量寻址来逐个比对长度、匹配字符,源码比较容易。

书本的测试代码如下:

#include <stdio.h>
#include "ngx_config.h"
#include "ngx_conf_file.h"
#include "nginx.h"
#include "ngx_core.h"
#include "ngx_string.h"
#include "ngx_palloc.h"
#include "ngx_array.h"
#include "ngx_hash.h"
volatile ngx_cycle_t *ngx_cycle;
void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, const char *fmt, ...) { }
static ngx_str_t names[] = {ngx_string("www.baidu.com"),
ngx_string("www.google.com.hk"),
ngx_string("www.github.com")};
static char* descs[] = {"baidu: 1","google: 2", "github: 3"};
// hash table的一些基本操作
int main()
{
    ngx_uint_t k;
    ngx_pool_t* pool;
ngx_hash_init_t hash_init;
ngx_hash_t* hash;
ngx_array_t* elements;
ngx_hash_key_t* arr_node;
char* find;
int i;
ngx_cacheline_size = 32;
pool = ngx_create_pool(1024*10, NULL);
/* 分配hash表基本结构内存 */
hash = (ngx_hash_t*) ngx_pcalloc(pool, sizeof(hash));
/* 初始化hash结构 */
hash_init.hash = hash; // hash结构
hash_init.key = &ngx_hash_key_lc; // hash函数
hash_init.max_size = 1024*10; // max_size
hash_init.bucket_size = 64;
hash_init.name = "test_hash_error";
hash_init.pool = pool;
hash_init.temp_pool = NULL;
/* 创建数组,把关键字压入到数组中 */
elements = ngx_array_create(pool, 32, sizeof(ngx_hash_key_t));
for(i = 0; i < 3; i++) {
arr_node = (ngx_hash_key_t*) ngx_array_push(elements);
arr_node->key = (names[i]);
arr_node->key_hash = ngx_hash_key_lc(arr_node->key.data, arr_node->key.len);
arr_node->value = (void*) descs[i];
printf("key: %s , key_hash: %u\n", arr_node->key.data, arr_node->key_hash);
}
/* hash初始化函数 */
if (ngx_hash_init(&hash_init, (ngx_hash_key_t*) elements->elts, elements->nelts) != NGX_OK){
return 1;
}
k = ngx_hash_key_lc(names[0].data, names[0].len);
printf("%s key is %d\n", names[0].data, k);
find = (char*)
ngx_hash_find(hash, k, (u_char*) names[0].data, names[0].len);
if (find) {
printf("get desc: %s\n",(char*) find);
}
ngx_array_destroy(elements);
ngx_destroy_pool(pool);
return 0;
}

接下来看一下红黑树,主要的数据结构是这两个:

typedef struct ngx_rbtree_node_s  ngx_rbtree_node_t;

struct ngx_rbtree_node_s {
    ngx_rbtree_key_t       key;
    ngx_rbtree_node_t     *left;
    ngx_rbtree_node_t     *right;
    ngx_rbtree_node_t     *parent;
    u_char                 color;
    u_char                 data;
};


typedef struct ngx_rbtree_s  ngx_rbtree_t;

typedef void (*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root,
    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);

struct ngx_rbtree_s {
    ngx_rbtree_node_t     *root;
    ngx_rbtree_node_t     *sentinel;
    ngx_rbtree_insert_pt   insert;
};

和普通树形结构不同,这个二叉树所有叶子节点的right left并不为空,而是指向这个ngx_rbtree_s.sentinel指针,在初始化时根节点的指针指向ngx_rbtree_s.sentinel,这个节点内部的键值默认为空。并且注意初始化时这个gx_rbtree_insert_pt函数是不可以为空的,需要用户层送入回调函数进行对树插入节点的操作,需要注意的是插入的节点颜色必须按规则置成红色,否则红黑树旋转会有异常。

nginx提供了一些红黑树的操作函数:

//对空的红黑树进行初始化,根节点和sentinel指向同一个节点,置黑色
#define ngx_rbtree_init(tree, s, i)                                           \
    ngx_rbtree_sentinel_init(s);                                              \
    (tree)->root = s;                                                         \
    (tree)->sentinel = s;                                                     \
    (tree)->insert = i

//往红黑树插入一个节点
void ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
//往红黑树删除一个节点
void ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);


//后面两个函数和红黑树中序遍历有关需要结合使用
ngx_rbtree_node_t *ngx_rbtree_next(ngx_rbtree_t *tree,
    ngx_rbtree_node_t *node);

static ngx_inline ngx_rbtree_node_t *
ngx_rbtree_min(ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);

现在提供演示代码,为了方便本人对源码做了一些处理:

//ngx_rbtree.c

/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */


//#include <ngx_config.h>
//#include <ngx_core.h>
#include"ngx_rbtree.h"
#include<stdio.h>
#include<stddef.h>

/*
 * The red-black tree code is based on the algorithm described in
 * the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
 */


static void ngx_rbtree_left_rotate(ngx_rbtree_node_t **root,
    ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node);
static void ngx_rbtree_right_rotate(ngx_rbtree_node_t **root,
    ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node);


void
ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
{
    ngx_rbtree_node_t  **root, *temp, *sentinel;

    /* a binary tree insert */

    root = &tree->root;
    sentinel = tree->sentinel;

    if (*root == sentinel) {
        node->parent = NULL;
        node->left = sentinel;
        node->right = sentinel;
        ngx_rbt_black(node);
        *root = node;

        return;
    }

    tree->insert(*root, node, sentinel);

    /* re-balance tree */

    while (node != *root && ngx_rbt_is_red(node->parent)) {

        if (node->parent == node->parent->parent->left) {
            temp = node->parent->parent->right;

            if (ngx_rbt_is_red(temp)) {
                ngx_rbt_black(node->parent);
                ngx_rbt_black(temp);
                ngx_rbt_red(node->parent->parent);
                node = node->parent->parent;

            } else {
                if (node == node->parent->right) {
                    node = node->parent;
                    ngx_rbtree_left_rotate(root, sentinel, node);
                }

                ngx_rbt_black(node->parent);
                ngx_rbt_red(node->parent->parent);
                ngx_rbtree_right_rotate(root, sentinel, node->parent->parent);
            }

        } else {
            temp = node->parent->parent->left;

            if (ngx_rbt_is_red(temp)) {
                ngx_rbt_black(node->parent);
                ngx_rbt_black(temp);
                ngx_rbt_red(node->parent->parent);
                node = node->parent->parent;

            } else {
                if (node == node->parent->left) {
                    node = node->parent;
                    ngx_rbtree_right_rotate(root, sentinel, node);
                }

                ngx_rbt_black(node->parent);
                ngx_rbt_red(node->parent->parent);
                ngx_rbtree_left_rotate(root, sentinel, node->parent->parent);
            }
        }
    }

    ngx_rbt_black(*root);
}


void
ngx_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
    ngx_rbtree_node_t *sentinel)
{
    ngx_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;
    ngx_rbt_red(node);
}


void
ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
    ngx_rbtree_node_t *sentinel)
{
    ngx_rbtree_node_t  **p;

    for ( ;; ) {

        /*
         * Timer values
         * 1) are spread in small range, usually several minutes,
         * 2) and overflow each 49 days, if milliseconds are stored in 32 bits.
         * The comparison takes into account that overflow.
         */

        /*  node->key < temp->key */

        p = ((ngx_rbtree_key_int_t) (node->key - temp->key) < 0)
            ? &temp->left : &temp->right;

        if (*p == sentinel) {
            break;
        }

        temp = *p;
    }

    *p = node;
    node->parent = temp;
    node->left = sentinel;
    node->right = sentinel;
    ngx_rbt_red(node);
}


void
ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
{
    ngx_uint_t           red;
    ngx_rbtree_node_t  **root, *sentinel, *subst, *temp, *w;

    /* a binary tree delete */

    root = &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 = ngx_rbtree_min(node->right, sentinel);

        if (subst->left != sentinel) {
            temp = subst->left;
        } else {
            temp = subst->right;
        }
    }

    if (subst == *root) {
        *root = temp;
        ngx_rbt_black(temp);

        /* DEBUG stuff */
        node->left = NULL;
        node->right = NULL;
        node->parent = NULL;
        node->key = 0;

        return;
    }

    red = ngx_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;
        ngx_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 && ngx_rbt_is_black(temp)) {

        if (temp == temp->parent->left) {
            w = temp->parent->right;

            if (ngx_rbt_is_red(w)) {
                ngx_rbt_black(w);
                ngx_rbt_red(temp->parent);
                ngx_rbtree_left_rotate(root, sentinel, temp->parent);
                w = temp->parent->right;
            }

            if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
                ngx_rbt_red(w);
                temp = temp->parent;

            } else {
                if (ngx_rbt_is_black(w->right)) {
                    ngx_rbt_black(w->left);
                    ngx_rbt_red(w);
                    ngx_rbtree_right_rotate(root, sentinel, w);
                    w = temp->parent->right;
                }

                ngx_rbt_copy_color(w, temp->parent);
                ngx_rbt_black(temp->parent);
                ngx_rbt_black(w->right);
                ngx_rbtree_left_rotate(root, sentinel, temp->parent);
                temp = *root;
            }

        } else {
            w = temp->parent->left;

            if (ngx_rbt_is_red(w)) {
                ngx_rbt_black(w);
                ngx_rbt_red(temp->parent);
                ngx_rbtree_right_rotate(root, sentinel, temp->parent);
                w = temp->parent->left;
            }

            if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
                ngx_rbt_red(w);
                temp = temp->parent;

            } else {
                if (ngx_rbt_is_black(w->left)) {
                    ngx_rbt_black(w->right);
                    ngx_rbt_red(w);
                    ngx_rbtree_left_rotate(root, sentinel, w);
                    w = temp->parent->left;
                }

                ngx_rbt_copy_color(w, temp->parent);
                ngx_rbt_black(temp->parent);
                ngx_rbt_black(w->left);
                ngx_rbtree_right_rotate(root, sentinel, temp->parent);
                temp = *root;
            }
        }
    }

    ngx_rbt_black(temp);
}


static void
ngx_rbtree_left_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
    ngx_rbtree_node_t *node)
{
    ngx_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 void
ngx_rbtree_right_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
    ngx_rbtree_node_t *node)
{
    ngx_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;
}


ngx_rbtree_node_t *
ngx_rbtree_next(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
{
    ngx_rbtree_node_t  *root, *sentinel, *parent;

    sentinel = tree->sentinel;

    if (node->right != sentinel) {
        return ngx_rbtree_min(node->right, sentinel);
    }

    root = tree->root;

    for ( ;; ) {
        parent = node->parent;

        if (node == root) {
            return NULL;
        }

        if (node == parent->left) {
            return parent;
        }

        node = parent;
    }
}
//ngx_rbtree.h
/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */


#ifndef _NGX_RBTREE_H_INCLUDED_
#define _NGX_RBTREE_H_INCLUDED_


//#include <ngx_config.h>
//#include <ngx_core.h>


typedef long    ngx_int_t;
typedef unsigned long       ngx_uint_t;
typedef long        ngx_flag_t;
typedef short int  u_char;


typedef ngx_uint_t  ngx_rbtree_key_t;
typedef ngx_int_t   ngx_rbtree_key_int_t;


typedef struct ngx_rbtree_node_s  ngx_rbtree_node_t;

struct ngx_rbtree_node_s {
    ngx_rbtree_key_t       key;
    ngx_rbtree_node_t     *left;
    ngx_rbtree_node_t     *right;
    ngx_rbtree_node_t     *parent;
    u_char                 color;
    unsigned char*         data;
};


typedef struct ngx_rbtree_s  ngx_rbtree_t;

typedef void (*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root,
    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);

struct ngx_rbtree_s {
    ngx_rbtree_node_t     *root;
    ngx_rbtree_node_t     *sentinel;
    ngx_rbtree_insert_pt   insert;
};


#define ngx_rbtree_init(tree, s, i)                                           \
    ngx_rbtree_sentinel_init(s);                                              \
    (tree)->root = s;                                                         \
    (tree)->sentinel = s;                                                     \
    (tree)->insert = i


void ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
void ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
void ngx_rbtree_insert_value(ngx_rbtree_node_t *root, ngx_rbtree_node_t *node,
    ngx_rbtree_node_t *sentinel);
void ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *root,
    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
ngx_rbtree_node_t *ngx_rbtree_next(ngx_rbtree_t *tree,
    ngx_rbtree_node_t *node);


#define ngx_rbt_red(node)               ((node)->color = 1)
#define ngx_rbt_black(node)             ((node)->color = 0)
#define ngx_rbt_is_red(node)            ((node)->color)
#define ngx_rbt_is_black(node)          (!ngx_rbt_is_red(node))
#define ngx_rbt_copy_color(n1, n2)      (n1->color = n2->color)


/* a sentinel must be black */

#define ngx_rbtree_sentinel_init(node)  ngx_rbt_black(node)


static ngx_rbtree_node_t *
ngx_rbtree_min(ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
{
    while (node->left != sentinel) {
        node = node->left;
    }

    return node;
}


#endif /* _NGX_RBTREE_H_INCLUDED_ */
//main.cpp
#include<stdio.h>
#include"ngx_rbtree.h"
#include<vector>
#include<string>
#include<math.h>
using namespace std;

vector<vector<long> > key;
vector<vector<string> > value;
vector<vector<short> > color;

long nLayer = 0;

void BLSNodeID(ngx_rbtree_node_t* ngx,ngx_rbtree_t* root,int col)
{
	if(key.size()==col)
	{
		vector<long> tmp;
		key.push_back(tmp);
		vector<string> tmp2;
		value.push_back(tmp2);
		vector<short> tmp3;
		color.push_back(tmp3);
	}
	//if(ngx->color==0)
	{
		key.at(col).push_back(ngx->key);
		value.at(col).push_back((char*)ngx->data);
		color.at(col).push_back(ngx->color);
		//printf("key:%d,value:%s \n ",ngx->key,ngx->data);
	}
	//else 
	//{
//	}
	if(ngx ==  root->sentinel)
		return;
	if(ngx->left != root->sentinel)
	{
		BLSNodeID(ngx->left,root,col+1);
	}
	if(ngx->right != root->sentinel)
	{
		BLSNodeID(ngx->right,root,col+1);
	}
} 

ngx_rbtree_node_t* findNode(int key,ngx_rbtree_t* tree,ngx_rbtree_node_t* currNode)
{
	if(currNode == tree->sentinel)
		return NULL;
	if(currNode->key == key)
		return currNode;
	//printf("%d!=%d\n",currNode->key,key);
	if(currNode->key < key)
	{
		return findNode(key,tree,currNode->left);
	}
	else
	{
		return findNode(key,tree,currNode->right);
	}
}

void insertCallBack(ngx_rbtree_node_t *root,
    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
{
	ngx_rbtree_node_t *t=root;
	while(t->left!=sentinel)
		t=t->left;
	t->left = node;	
	node->color = 1;//new node should be red
	node->left = sentinel;
	node->right = sentinel;
	node->parent = t;
}


ngx_rbtree_t root;

void printRBTree()
{
	key.clear();
	value.clear();
	color.clear();	
	BLSNodeID((root.root),&root,0);

	for(int i = 0;i<key.size();++i)
	{
		int cnt = pow(2,key.size())-i;
		for(int l=0;l<cnt;++l)
			printf(" ");
		for(int j=0;j<key.at(i).size();++j)
		{	
			if(color[i][j]==0)
			{	
			    	printf("%d ",key[i][j]);
			}
			else
			{
				printf("\033[41m\033[1m");
				printf("%d ",key[i][j]);
				printf("\033[0m");
			}
		//[i][j]
		}
		printf("\n");
	}
	printf("==================\n");		
}

int main()
{
	ngx_rbtree_node_t nodeSential;
	ngx_rbtree_init(&root,&nodeSential,insertCallBack);

	/*
	ngx_rbtree_node_t node1;
	node1.key=6;
	unsigned char a[11]={"11111\0"};
	node1.data = a;	
	ngx_rbtree_insert(&root,&node1);

	printRBTree();


	ngx_rbtree_node_t node2;
        node2.key=7;
        unsigned char b[11]={"133331\0"};
        node2.data = b;	
	ngx_rbtree_insert(&root,&node2);

	printRBTree();
	ngx_rbtree_node_t node3;
        node3.key=2;
        unsigned char c[11]={"1234211\0"};
        node3.data = c;
        ngx_rbtree_insert(&root,&node3);	
	
	printRBTree();
	
	ngx_rbtree_node_t node4;
        node4.key=8;
        unsigned char d[11]={"8888888\0"};
        node4.data = d;
        ngx_rbtree_insert(&root,&node4);

	printRBTree();

	ngx_rbtree_node_t node5;
        node5.key=1;
        unsigned char e[11]={"1221211\0"};
        node5.data = e;
        ngx_rbtree_insert(&root,&node5);	
	printRBTree();
	

	ngx_rbtree_node_t node6;
        node6.key=9;
        unsigned char f[11]={"12fff1\0"};
        node6.data = e;
        ngx_rbtree_insert(&root,&node6);	
	printRBTree();*/

	unsigned char data[11]={"12fff1\0"};
	for(int i=0;i<10;++i)
	{
		ngx_rbtree_node_t* node = new ngx_rbtree_node_t;
		node->key = i;
		node->data = data;
		ngx_rbtree_insert(&root,node);
		printRBTree();
	}
	
	ngx_rbtree_node_t* minNode = ngx_rbtree_min(root.root,root.sentinel);
	printf("%d ",minNode->key);
	ngx_rbtree_node_t* tmpPtr=minNode;	
	while((tmpPtr=ngx_rbtree_next(&root,tmpPtr))!=NULL)
	{
             printf("%d ",tmpPtr->key);
	}
	printf("\n**************************************\n");
	
	for(int i=5;i<10;++i)
        {
		if(findNode(i,&root,root.root))
                	ngx_rbtree_delete(&root,findNode(i,&root,root.root));
                printRBTree();
        }


	//free ngx_rbtree_node_t*
		
	return 0;
}

执行编译:g++ main.cpp ngx_rbtree.c -g -o main。运行即可看到整个红黑树的插入节点、遍历打印节点和删除过程:

插入数据:

中序遍历:

删除节点

可结合红黑树的性质来看。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值