日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2025/3/21 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 新秀nginx源代码分析数据结构篇(四)红黑树ngx_rbtree_t 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

新秀nginx源代碼分析數據結構篇(四)紅黑樹ngx_rbtree_t

?

Author:Echo Chen(陳斌)

Email:chenb19870707@gmail.com

Blog:Blog.csdn.net/chen19870707

Date:October 27h, 2014

?

?

1.ngx_rbtree優勢和特點

?

??? ngx_rbtree是一種使用紅黑樹實現的關聯容器。關于紅黑樹的特性,在《手把手實現紅黑樹》已經具體介紹,這里就僅僅探討ngx_rbtree與眾不同的地方;ngx_rbtree紅黑樹容器中的元素都是有序的,支持高速索引,插入,刪除操作,也支持范圍查詢,遍歷操作。應用很廣泛。

?

2.源碼位置

?

頭文件:http://trac.nginx.org/nginx/browser/nginx/src/core/ngx_rbtree.h

源文件:http://trac.nginx.org/nginx/browser/nginx/src/core/ngx_rbtree.c

?

3.數據結構定義

?

能夠看到ngx_rbtree的結點ngx_rbtree_node_t結構跟一般的紅黑樹差點兒相同,都是由鍵值key、左孩子left、右孩子right、父親結點parent、顏色值color,不同的是ngx_rbtree_node_t這里多了一個data。但依據官方文檔記在,因為data僅僅有一個字節,表示太少,非常少使用到

1: typedef?struct ngx_rbtree_node_s? ngx_rbtree_node_t; 2:? 3: struct ngx_rbtree_node_s { 4:???? ngx_rbtree_key_t?????? key; 5:???? ngx_rbtree_node_t???? *left; 6:???? ngx_rbtree_node_t???? *right; 7:???? ngx_rbtree_node_t???? *parent; 8:???? u_char???????????????? color; 9:???? u_char???????????????? data; 10: };

?

ngx_rbtree_t的結構也與一般紅黑樹同樣,右root結點和哨兵葉子結點(sentinel)組成,不同的是這里多了一個 函數指針inserter。它決定了在加入結點是新加還是替換。

?

1: typedef?struct ngx_rbtree_s? ngx_rbtree_t; 2:? 3: typedef?void (*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root, 4:???? ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); 5:? 6: struct ngx_rbtree_s { 7:???? ngx_rbtree_node_t???? *root; 8:???? ngx_rbtree_node_t???? *sentinel; 9:???? ngx_rbtree_insert_pt?? insert; 10: };

?

4.ngx_rbtree初始化 ngx_rbtree_init

?

當中tree為ngx_rbtree_t類型,即為紅黑樹。s為ngx_rbtree_node_t,是rbtree的根節點,i即為上節提到的決定插入是新結點還是替換的函數指針。首先將根節點涂成 黑色(紅黑樹基本性質)。然后把 紅黑樹的 根節點和 哨兵結點 都指向這個結點。

?

1: #define ngx_rbtree_init(tree, s, i)?????????????????????????????????????????? \ 2:???? ngx_rbtree_sentinel_init(s);????????????????????????????????????????????? \ 3:???? (tree)->root = s;???????????????????????????????????????????????????????? \ 4:???? (tree)->sentinel = s;???????????????????????????????????????????????????? \ 5:???? (tree)->insert = i 6:? 7: #define ngx_rbtree_sentinel_init(node)? ngx_rbt_black(node)

?

5.ngx_rbtree 左旋 ngx_rbtree_left_rotate 和 右旋 ngx_rbtree_right_rotate

?

能夠看到,經典代碼總是永恒的,ngx_rbtree的左旋右旋也是參考《算法導論》導論中的步驟和偽代碼。對比我自己的實現的《手把手實現紅黑樹》,與我自己實現的左旋右旋代碼基本一致。我圖解了具體的過程,有不清楚的能夠參考《手把手實現紅黑樹》。

?

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:? 7:???? temp = node->right; 8:???? node->right = temp->left; 9:? 10:???? if (temp->left != sentinel) { 11:???????? temp->left->parent = node; 12:???? } 13:? 14:???? temp->parent = node->parent; 15:? 16:???? if (node == *root) { 17:???????? *root = temp; 18:? 19:???? } else?if (node == node->parent->left) { 20:???????? node->parent->left = temp; 21:? 22:???? } else { 23:???????? node->parent->right = temp; 24:???? } 25:? 26:???? temp->left = node; 27:???? node->parent = temp; 28: }

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:? 7:???? temp = node->left; 8:???? node->left = temp->right; 9:? 10:???? if (temp->right != sentinel) { 11:???????? temp->right->parent = node; 12:???? } 13:? 14:???? temp->parent = node->parent; 15:? 16:???? if (node == *root) { 17:???????? *root = temp; 18:? 19:???? } else?if (node == node->parent->right) { 20:???????? node->parent->right = temp; 21:? 22:???? } else { 23:???????? node->parent->left = temp; 24:???? } 25:? 26:???? temp->right = node; 27:???? node->parent = temp; 28: }

6.ngx_rbtree插入 ngx_rbtree_insert

ngx_rbtree_insert也是分為兩步,插入和調整。因為這兩項都在《手把手實現紅黑樹》中做了詳解,這里就不在啰嗦。這里值得一提的是,還記得node_rbtree_t 結構中的insert指針嗎?這里就是通過這個函數指針來實現的插入。

一個小小的技巧就實現了多態。而且它給出了 唯一值和時間類型的key 插入方法。能夠滿足一般需求,用戶也能夠實現自己的插入方法。

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); }

6.1 唯一值類型插入

?

這個即為一般紅黑樹的插入方法,循環,假設插入的值比當前節點小,就進入左子樹,否則進入右子樹。直至遇到葉子結點。葉子節點就是要鏈入紅黑樹的位置。

1: void 2: ngx_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, 3:???? ngx_rbtree_node_t *sentinel) 4: { 5:???? ngx_rbtree_node_t? **p; 6:? 7:???? for ( ;; ) { 8:? 9:???????? p = (node->key < temp->key) ? &temp->left : &temp->right; 10:? 11:???????? if (*p == sentinel) { 12:???????????? break; 13:???????? } 14:? 15:???????? temp = *p; 16:???? } 17:? 18:???? *p = node; 19:???? node->parent = temp; 20:???? node->left = sentinel; 21:???? node->right = sentinel; 22:???? ngx_rbt_red(node); 23: }

假設有相等的結點。會直接被覆蓋,如上圖插入key為2的結點,則當tmp 為2的結點時。p為葉子遍歷結束。這樣p就會被覆蓋為新的值。

?

6.2 唯一時間類型插入

?

唯一差別就是推斷大小時,採用了兩個值相減,避免溢出。

1: typedef ngx_int_t?? ngx_rbtree_key_int_t; 2: void 3: ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, 4:???? ngx_rbtree_node_t *sentinel) 5: { 6:???? ngx_rbtree_node_t? **p; 7:? 8:???? for ( ;; ) { 9:? 10:???????? /* 11: ???????? * Timer values 12: ???????? * 1) are spread in small range, usually several minutes, 13: ???????? * 2) and overflow each 49 days, if milliseconds are stored in 32 bits. 14: ???????? * The comparison takes into account that overflow. 15: ???????? */ 16:? 17:???????? /*? node->key < temp->key */ 18:? 19:??????? p = ((ngx_rbtree_key_int_t) (node->key - temp->key) < 0) 20:???????????? ? &temp->left : &temp->right; 21:? 22:???????? if (*p == sentinel) { 23:???????????? break; 24:???????? } 25:? 26:???????? temp = *p; 27:???? } 28:? 29:???? *p = node; 30:???? node->parent = temp; 31:???? node->left = sentinel; 32:???? node->right = sentinel; 33:???? ngx_rbt_red(node); 34: }

?

?

7.ngx_rbtree刪除ngx_rbtree_delete

也是依照《算法導論》上的步驟,先刪除后調整,在《手把手實現紅黑樹》已介紹,請參考

1: void 2: ngx_rbtree_delete_delete(ngx_thread_volatile ngx_rbtree_t *tree, 3:???? ngx_rbtree_node_t *node) 4: { 5:???? ngx_uint_t?????????? red; 6:???? ngx_rbtree_node_t? **root, *sentinel, *subst, *temp, *w; 7:? 8:???? /* a binary tree delete */ 9:? 10:???? root = (ngx_rbtree_node_t **) &tree->root; 11:???? sentinel = tree->sentinel; 12:? 13:???? if (node->left == sentinel) { 14:???????? temp = node->right; 15:???????? subst = node; 16:? 17:???? } else?if (node->right == sentinel) { 18:???????? temp = node->left; 19:???????? subst = node; 20:? 21:???? } else { 22:???????? subst = ngx_rbtree_min(node->right, sentinel); 23:? 24:???????? if (subst->left != sentinel) { 25:???????????? temp = subst->left; 26:???????? } else { 27:???????????? temp = subst->right; 28:???????? } 29:???? } 30:? 31:???? if (subst == *root) { 32:???????? *root = temp; 33:???????? ngx_rbt_black(temp); 34:? 35:???????? /* DEBUG stuff */ 36:???????? node->left = NULL; 37:???????? node->right = NULL; 38:???????? node->parent = NULL; 39:???????? node->key = 0; 40:? 41:???????? return; 42:???? } 43:? 44:???? red = ngx_rbt_is_red(subst); 45:? 46:???? if (subst == subst->parent->left) { 47:???????? subst->parent->left = temp; 48:? 49:???? } else { 50:???????? subst->parent->right = temp; 51:???? } 52:? 53:???? if (subst == node) { 54:? 55:???????? temp->parent = subst->parent; 56:? 57:???? } else { 58:? 59:???????? if (subst->parent == node) { 60:???????????? temp->parent = subst; 61:? 62:???????? } else { 63:???????????? temp->parent = subst->parent; 64:???????? } 65:? 66:???????? subst->left = node->left; 67:???????? subst->right = node->right; 68:???????? subst->parent = node->parent; 69:???????? ngx_rbt_copy_color(subst, node); 70:? 71:???????? if (node == *root) { 72:???????????? *root = subst; 73:? 74:???????? } else { 75:???????????? if (node == node->parent->left) { 76:???????????????? node->parent->left = subst; 77:???????????? } else { 78:???????????????? node->parent->right = subst; 79:???????????? } 80:???????? } 81:? 82:???????? if (subst->left != sentinel) { 83:???????????? subst->left->parent = subst; 84:???????? } 85:? 86:???????? if (subst->right != sentinel) { 87:???????????? subst->right->parent = subst; 88:???????? } 89:???? } 90:? 91:???? /* DEBUG stuff */ 92:???? node->left = NULL; 93:???? node->right = NULL; 94:???? node->parent = NULL; 95:???? node->key = 0; 96:? 97:???? if (red) { 98:???????? return; 99:???? } 100:? 101:???? /* a delete fixup */ 102:? 103:???? while (temp != *root && ngx_rbt_is_black(temp)) { 104:? 105:???????? if (temp == temp->parent->left) { 106:???????????? w = temp->parent->right; 107:? 108:???????????? if (ngx_rbt_is_red(w)) { 109:???????????????? ngx_rbt_black(w); 110:???????????????? ngx_rbt_red(temp->parent); 111:???????????????? ngx_rbtree_left_rotate(root, sentinel, temp->parent); 112:???????????????? w = temp->parent->right; 113:???????????? } 114:? 115:???????????? if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) { 116:???????????????? ngx_rbt_red(w); 117:???????????????? temp = temp->parent; 118:? 119:???????????? } else { 120:???????????????? if (ngx_rbt_is_black(w->right)) { 121:???????????????????? ngx_rbt_black(w->left); 122:???????????????????? ngx_rbt_red(w); 123:???????????????????? ngx_rbtree_right_rotate(root, sentinel, w); 124:???????????????????? w = temp->parent->right; 125:???????????????? } 126:? 127:???????????????? ngx_rbt_copy_color(w, temp->parent); 128:???????????????? ngx_rbt_black(temp->parent); 129:???????????????? ngx_rbt_black(w->right); 130:???????????????? ngx_rbtree_left_rotate(root, sentinel, temp->parent); 131:???????????????? temp = *root; 132:???????????? } 133:? 134:???????? } else { 135:???????????? w = temp->parent->left; 136:? 137:???????????? if (ngx_rbt_is_red(w)) { 138:???????????????? ngx_rbt_black(w); 139:???????????????? ngx_rbt_red(temp->parent); 140:???????????????? ngx_rbtree_right_rotate(root, sentinel, temp->parent); 141:???????????????? w = temp->parent->left; 142:???????????? } 143:? 144:???????????? if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) { 145:???????????????? ngx_rbt_red(w); 146:???????????????? temp = temp->parent; 147:? 148:???????????? } else { 149:???????????????? if (ngx_rbt_is_black(w->left)) { 150:???????????????????? ngx_rbt_black(w->right); 151:???????????????????? ngx_rbt_red(w); 152:???????????????????? ngx_rbtree_left_rotate(root, sentinel, w); 153:???????????????????? w = temp->parent->left; 154:???????????????? } 155:? 156:???????????????? ngx_rbt_copy_color(w, temp->parent); 157:???????????????? ngx_rbt_black(temp->parent); 158:???????????????? ngx_rbt_black(w->left); 159:???????????????? ngx_rbtree_right_rotate(root, sentinel, temp->parent); 160:???????????????? temp = *root; 161:???????????? } 162:???????? } 163:???? } 164:? 165:???? ngx_rbt_black(temp); 166: }

?

8.實戰

?

因為ngx_rbtree_t未牽涉到內存池,所以很easy抽出來使用,例如以下為實現了插入、打印最小值、刪除的樣例

1: #include <iostream> 2: #include <algorithm> 3: #include <pthread.h> 4: #include <time.h> 5: #include <stdio.h> 6: #include <errno.h> 7: #include <string.h> 8: #include "ngx_queue.h" 9: #include "ngx_rbtree.h" 10:? 11:? 12: int main() 13: { 14:? 15:???? ngx_rbtree_t tree; 16:???? ngx_rbtree_node_t sentinel; 17:? 18:???? ngx_rbtree_init(&tree,&sentinel,ngx_rbtree_insert_value); 19:? 20:???? ngx_rbtree_node_t *rbnode = new ngx_rbtree_node_t[100]; 21:???? for(int i = 99; i >= 0 ;i--) 22:???? { 23:???????? rbnode[i].key = i; 24:???????? rbnode[i].parent = NULL; 25:???????? rbnode[i].left = NULL; 26:???????? rbnode[i].right = NULL; 27:???????? ngx_rbtree_insert(&tree,&rbnode[i]); 28:???? } 29:? 30:???? for(int i = 0; i < 100;i++) 31:???? { 32:????????? ngx_rbtree_node_t *p = ngx_rbtree_min(tree.root,&sentinel); 33:????????? std::cout << p->key << "? "; 34:????????? ngx_rbtree_delete(&tree,p); 35:????? } 36:? 37:? 38:???? delete[] rbnode; 39:? 40:???? return 0; 41: }

?

執行結果:


-

Echo Chen:Blog.csdn.net/chen19870707

-

版權聲明:本文博客原創文章,博客,未經同意,不得轉載。

總結

以上是生活随笔為你收集整理的新秀nginx源代码分析数据结构篇(四)红黑树ngx_rbtree_t的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。