/*

 * 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 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 {

    // 无符号整形的keyword

    ngx_rbtree_key_t       key;

    // 左子节点

    ngx_rbtree_node_t     *left;

    // 右子节点

    ngx_rbtree_node_t     *right;

    // 父节点

    ngx_rbtree_node_t     *parent;

    // 节点的颜色,0表示黑色。1表示红色

    u_char                 color;

    // 仅1个字节的节点数据。

因为表示的空间太小,所以一般非常少使用。

    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;

    // 指向NIL哨兵节点

    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_thread_volatile ngx_rbtree_t *tree,

    ngx_rbtree_node_t *node);

void ngx_rbtree_delete(ngx_thread_volatile 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);









#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_inline 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_ */

/*

 * Copyright (C) Igor Sysoev

 * Copyright (C) Nginx, Inc.

 */





#include <ngx_config.h>

#include <ngx_core.h>





/*

 * The red-black tree code is based on the algorithm described in

 * the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.

 */





static ngx_inline void ngx_rbtree_left_rotate(ngx_rbtree_node_t **root,

ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node);

static ngx_inline 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_thread_volatile ngx_rbtree_t *tree,

ngx_rbtree_node_t *node) {

ngx_rbtree_node_t **root, *temp, *sentinel;





/* a binary tree insert */





root = (ngx_rbtree_node_t **) &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 - (ngx_rbtree_key_int_t) 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_thread_volatile 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 = (ngx_rbtree_node_t **) &tree->root;

sentinel = tree->sentinel;

//找到y和x节点

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;

}

}

//y节点为root节点

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);//记录y节点颜色

//y父的孩子节点

if (subst == subst->parent->left) {

subst->parent->left = temp;





} else {

subst->parent->right = temp;

}

//y孩子的父节点

if (subst == node) {//仅仅有一个孩子节点





temp->parent = subst->parent;





} else {





if (subst->parent == node) {

temp->parent = subst;





} else {

temp->parent = subst->parent;

}

//y节点copy z节点属性

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;

}

}

//y节点的父节点

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 ngx_inline 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;





//1、设置节点y

temp = node->right;

//2、将y的左子树作为x的右子树

node->right = temp->left;

if (temp->left != sentinel) {

temp->left->parent = node;

}

//3、链接y与x的父节点

temp->parent = node->parent;





if (node == *root) {

*root = temp;

} else if (node == node->parent->left) {

node->parent->left = temp;

} else {

node->parent->right = temp;

}

//4、x作为y的左子树

temp->left = node;

node->parent = temp;

}





static ngx_inline 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;

}

Nginx之红黑树的更多相关文章

  1. 定时器管理:nginx的红黑树和libevent的堆

    libevent 发生超时后, while循环一次从堆顶del timer——直到最新调整的最小堆顶不是超时事件为止,(实际是del event),但是会稍后把这个timeout的 event放到ac ...

  2. 红黑树、B(+)树、跳表、AVL等数据结构,应用场景及分析,以及一些英文缩写

    在网上学习了一些材料. 这一篇:https://www.zhihu.com/question/30527705 AVL树:最早的平衡二叉树之一.应用相对其他数据结构比较少.windows对进程地址空间 ...

  3. 简单聊聊红黑树(Red Black Tree)

    ​ 前言 众所周知,红黑树是非常经典,也很非常重要的数据结构,自从1972年被发明以来,因为其稳定高效的特性,40多年的时间里,红黑树一直应用在许多系统组件和基础类库中,默默无闻的为我们提供服务,身边 ...

  4. 红黑树和AVL树的区别(转)

    add by zhj: AVL树和红黑树都是平衡二叉树,虽然AVL树是最早发明的平衡二叉树,但直接把平衡二叉树等价于AVL树,我认为非常不合适. 但很多地方都在这么用.两者的比较如下 平衡二叉树类型 ...

  5. 新秀nginx源代码分析数据结构篇(四)红黑树ngx_rbtree_t

    新秀nginx源代码分析数据结构篇(四)红黑树ngx_rbtree_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csd ...

  6. nginx 红黑树详解

    1 介绍 这部分终于整理完了,太耗时间了,留下来备忘吧! 之前看STL源码时,只是研究了红黑树的插入部分.在stl源码剖析的书中,也没有涉及到删除操作的分析,这次对删除操作也进行了详细的研究, 并且还 ...

  7. 在nginx启动后,如果我们要操作nginx,要怎么做呢 别增加无谓的上下文切换 异步非阻塞的方式来处理请求 worker的个数为cpu的核数 红黑树

    nginx平台初探(100%) — Nginx开发从入门到精通 http://ten 众所周知,nginx性能高,而nginx的高性能与其架构是分不开的.那么nginx究竟是怎么样的呢?这一节我们先来 ...

  8. 菜鸟nginx源码剖析数据结构篇(四)红黑树ngx_rbtree_t[转]

    菜鸟nginx源码剖析数据结构篇(四)红黑树ngx_rbtree_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csdn ...

  9. Nginx数据结构之红黑树ngx_rbtree_t

    1. 什么是红黑树? 1.1 概述 红黑树实际上是一种自平衡二叉查找树. 二叉树是什么?二叉树是每个节点最多有两个子树的树结构,每个节点都可以用于存储数据,可以由任 1 个节点访问它的左右 子树或父节 ...

随机推荐

  1. hdu 5158(水题)

    Have meal Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  2. Reporting Service报表水印的添加

    上一篇文章寫到了自帶報表的製作,現在來談談報表水印的添加 1:水印產生代碼 using System; using System.Data; using System.Configuration; u ...

  3. 计蒜客 28201.Choosing Ice Cream-gcd (BAPC 2014 Preliminary ACM-ICPC Asia Training League 暑假第一阶段第一场 A)

    开始水一波博客 题目链接: A. Choosing Ice Cream 传送门 题意就是n个冰淇淋,骰子有k个面,问你是否能在公平的概率下转几次骰子能确定买哪个冰淇淋. 举个例子,假设我只有一个冰淇淋 ...

  4. Codeforces 570D - Tree Requests(树上启发式合并)

    570D - Tree Requests 题意 给出一棵树,每个节点上有字母,查询 u k,问以 u 为根节点的子树下,深度为 k 的所有子节点上的字母经过任意排列是否能构成回文串. 分析 一个数组 ...

  5. ACM入门指南

    本文已经转移到了:http://harryguo.me/2015/11/03/ACM-%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/ 什么是ACM? 想必打开这篇博客的人已 ...

  6. Lucas定理模板【bzoj2982】【combination】

    (上不了p站我要死了,侵权度娘背锅) Description LMZ有n个不同的基友,他每天晚上要选m个进行[河蟹],而且要求每天晚上的选择都不一样.那么LMZ能够持续多少个这样的夜晚呢?当然,LMZ ...

  7. 第八章 android-布局

    常用的布局实现方式:线性布局,框架布局,表格布局,相对布局,绝对布局 1,线性布局 (1)线性布局是一种很重要的布局,也是经常用到的一种布局 (2)在线性布局中,所有的元素都按照水平竖直的顺序在界面上 ...

  8. shell 调用 sqlplus

    一.最简单的shell里调用sqlplus. $ vi test1.sh #!/bin/bashsqlplus -S /nolog > result.log <<EOFset hea ...

  9. 【视频】Linux高级程序设计01.3命令行选项及参数

    [课程笔记] [命令行参数] 选项:-l -a -i 参数:-l /home main 函数形式: int main(int argc, char *argv[]) main函数是有参数的,而且有返回 ...

  10. linux命令详解:jobs命令

    转:http://www.cnblogs.com/lwgdream/p/3413571.html 前言 我们可以将一个程序放到后台执行,这样它就不占用当前终端,我们可以做其他事情.而jobs命令用来查 ...