• Nginx源码解析 --红黑树


    预读知识

    红黑树是一种自平衡二叉树,不仅可以使用二分法快速查找,而且插入和删除操作的效率也很高,常用于构造关联数组(例如C++标准库里的set和 map)。

    在Nginx里红黑树主要用在事件机制里的定时器,检查连接超时,此外还在reslover、cache里用于快速查找。

     红黑树概要_编程界的谢菲尔德的博客-CSDN博客

    1. 节点不是黑色,就是红色(非黑即红)
    2. 根节点为黑色
    3. 叶节点为黑色(叶节点是指末梢的空节点 NilNull
    4. 一个节点为红色,则其两个子节点必须是黑色的(根到叶子的所有路径,不可能存在两个连续的红色节点)
    5. 每个节点到叶子节点的所有路径,都包含相同数目的黑色节点(相同的黑色高度)

    基本数据结构

    1. typedef ngx_uint_t ngx_rbtree_key_t;
    2. typedef ngx_int_t ngx_rbtree_key_int_t;
    3. typedef struct ngx_rbtree_node_s ngx_rbtree_node_t;
    4. struct ngx_rbtree_node_s {
    5. ngx_rbtree_key_t key;
    6. ngx_rbtree_node_t *left;
    7. ngx_rbtree_node_t *right;
    8. ngx_rbtree_node_t *parent;
    9. u_char color;
    10. u_char data;
    11. };
    12. typedef struct ngx_rbtree_s ngx_rbtree_t;
    13. typedef void (*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root,
    14. ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
    15. struct ngx_rbtree_s {
    16. ngx_rbtree_node_t *root;
    17. ngx_rbtree_node_t *sentinel;
    18. ngx_rbtree_insert_pt insert;
    19. };

    结构定义

    1.

    typedef ngx_uint_t  ngx_rbtree_key_t;                 //无符号
    typedef ngx_int_t   ngx_rbtree_key_int_t;           //有符号

    2结点                                           //侵入容器

    ngx_rbtree_key_t         key;       //红黑树的键 用于排序比较

     ngx_rbtree_node_t     *left;      //左指针
     ngx_rbtree_node_t     *right;    //右指针
     ngx_rbtree_node_t     *parent; //父结点
     u_char                          color;    // 1代表 0代表 黑色
     u_char                          data;     // 无意义

    3 树                                            

     ngx_rbtree_node_t     *root;           //红黑树的根节点:           
     ngx_rbtree_node_t     *sentinel;     //红黑树的哨兵节点,用于简化实现,它总是黑色的;
     ngx_rbtree_insert_pt   insert;         //节点的插入方法,允许对特殊节点定制特殊插入方法

    4. 内存布局

     

    2.操作函数

    1.初始化(红为一  黑为0 同时也代表 正负)

    1. #define ngx_rbt_red(node) ((node)->color = 1)
    2. #define ngx_rbt_black(node) ((node)->color = 0)
    3. #define ngx_rbt_is_red(node) ((node)->color)
    4. #define ngx_rbt_is_black(node) (!ngx_rbt_is_red(node))
    5. #define ngx_rbt_copy_color(n1, n2) (n1->color = n2->color)
    6. #define ngx_rbtree_sentinel_init(node) ngx_rbt_black(node)
    7. #define ngx_rbtree_init(tree, s, i) \
    8. ngx_rbtree_sentinel_init(s); \
    9. (tree)->root = s; \
    10. (tree)->sentinel = s; \
    11. (tree)->insert = i
    ngx_rbtree_init实际上是一个宏,初始化后红黑树里仅有一个哨兵节点s,它同时也是根节点。

    2.辅助函数 (旋转函数)(个人建议 直接看红黑树概要_编程界的谢菲尔德的博客-CSDN博客

    1.左旋

    1. static ngx_inline void
    2. ngx_rbtree_left_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
    3. ngx_rbtree_node_t *node)
    4. {
    5. ngx_rbtree_node_t *temp;
    6. temp = node->right;
    7. node->right = temp->left;
    8. if (temp->left != sentinel) {
    9. temp->left->parent = node;
    10. }
    11. temp->parent = node->parent;
    12. if (node == *root) {
    13. *root = temp;
    14. } else if (node == node->parent->left) {
    15. node->parent->left = temp;
    16. } else {
    17. node->parent->right = temp;
    18. }
    19. temp->left = node;
    20. node->parent = temp;
    21. }

    2.右旋

    1. static ngx_inline void
    2. ngx_rbtree_right_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
    3. ngx_rbtree_node_t *node)
    4. {
    5. ngx_rbtree_node_t *temp;
    6. temp = node->left;
    7. node->left = temp->right;
    8. if (temp->right != sentinel) {
    9. temp->right->parent = node;
    10. }
    11. temp->parent = node->parent;
    12. if (node == *root) {
    13. *root = temp;
    14. } else if (node == node->parent->right) {
    15. node->parent->right = temp;
    16. } else {
    17. node->parent->left = temp;
    18. }
    19. temp->right = node;
    20. node->parent = temp;
    21. }

    3.删除

    1. void
    2. ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
    3. {
    4. ngx_uint_t red;
    5. ngx_rbtree_node_t **root, *sentinel, *subst, *temp, *w;
    6. /* a binary tree delete */
    7. root = &tree->root;
    8. sentinel = tree->sentinel;
    9. if (node->left == sentinel) {
    10. temp = node->right;
    11. subst = node;
    12. } else if (node->right == sentinel) {
    13. temp = node->left;
    14. subst = node;
    15. } else {
    16. subst = ngx_rbtree_min(node->right, sentinel);
    17. if (subst->left != sentinel) {
    18. temp = subst->left;
    19. } else {
    20. temp = subst->right;
    21. }
    22. }
    23. if (subst == *root) {
    24. *root = temp;
    25. ngx_rbt_black(temp);
    26. /* DEBUG stuff */
    27. node->left = NULL;
    28. node->right = NULL;
    29. node->parent = NULL;
    30. node->key = 0;
    31. return;
    32. }
    33. red = ngx_rbt_is_red(subst);
    34. if (subst == subst->parent->left) {
    35. subst->parent->left = temp;
    36. } else {
    37. subst->parent->right = temp;
    38. }
    39. if (subst == node) {
    40. temp->parent = subst->parent;
    41. } else {
    42. if (subst->parent == node) {
    43. temp->parent = subst;
    44. } else {
    45. temp->parent = subst->parent;
    46. }
    47. subst->left = node->left;
    48. subst->right = node->right;
    49. subst->parent = node->parent;
    50. ngx_rbt_copy_color(subst, node);
    51. if (node == *root) {
    52. *root = subst;
    53. } else {
    54. if (node == node->parent->left) {
    55. node->parent->left = subst;
    56. } else {
    57. node->parent->right = subst;
    58. }
    59. }
    60. if (subst->left != sentinel) {
    61. subst->left->parent = subst;
    62. }
    63. if (subst->right != sentinel) {
    64. subst->right->parent = subst;
    65. }
    66. }
    67. /* DEBUG stuff */
    68. node->left = NULL;
    69. node->right = NULL;
    70. node->parent = NULL;
    71. node->key = 0;
    72. if (red) {
    73. return;
    74. }
    75. /* a delete fixup */
    76. while (temp != *root && ngx_rbt_is_black(temp)) {
    77. if (temp == temp->parent->left) {
    78. w = temp->parent->right;
    79. if (ngx_rbt_is_red(w)) {
    80. ngx_rbt_black(w);
    81. ngx_rbt_red(temp->parent);
    82. ngx_rbtree_left_rotate(root, sentinel, temp->parent);
    83. w = temp->parent->right;
    84. }
    85. if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
    86. ngx_rbt_red(w);
    87. temp = temp->parent;
    88. } else {
    89. if (ngx_rbt_is_black(w->right)) {
    90. ngx_rbt_black(w->left);
    91. ngx_rbt_red(w);
    92. ngx_rbtree_right_rotate(root, sentinel, w);
    93. w = temp->parent->right;
    94. }
    95. .....

    4.插入

    1.首先包装一个整的

    ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)

    2.分类

    2.1void  ngx_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
        ngx_rbtree_node_t *sentinel)    //这个是一个数值插入

    2.2 void ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
        ngx_rbtree_node_t *sentinel)    定时器红黑树的专用插入函数,键值是毫秒值

    2.3 (字符串头文件里)

    void ngx str_rbtree_insert_value ngx_rbtree_node_t *temp ,

    ngx_rbtree_node_t *node , ngx_rbtree_node_t *sentinel);
    //字符串红黑树的专用插入函数,键值是字符串的hash值



     

  • 相关阅读:
    [SystemC]SystemC Hierarchical Channels
    MySQL:日志系统介绍 | 错误日志 | 查询日志 | 二进制日志:bin-log数据恢复实践 | 慢日志查询
    AUTOCAD——LEN命令
    Jmeter集成到jenkins
    【抓包分析】通过ChatGPT解密还原某软件登录算法实现绕过手机验证码登录
    单元测试框架-Pytest(简单学习)
    Redis介绍、安装与初体验
    unity 骨骼物理 头发 布料模拟
    SpringBoot
    前后端分离Vue+nodejs酒店公寓客房预订管理系统udr7l-java-php-django-springboot
  • 原文地址:https://blog.csdn.net/qq_62309585/article/details/128055303