/* * red_black.h */ #ifndef _RED_BLACK_H #define _RED_BLACK_H typedef enum _color_t { RED, BLACK }color_t; typedef struct _red_black_t { int data; color_t color; struct _red_black_t *parent; struct _red_black_t *left; struct _red_black_t *right; }red_black_t; extern int init_rbt(red_black_t **root, int value); extern void delete_rbt(red_black_t *root); extern red_black_t* rbt_insert(red_black_t *root, int value); extern int rbt_delete(red_black_t **root, int value); extern void rbt_print_preorder(red_black_t *root); extern red_black_t* rbt_search(red_black_t *root, int value); extern int rbt_get_height(red_black_t *root); #endif
/* * red_black.c */ /* * 紅黑樹性質: * 1. 每個結點或紅或黑。 * 2. 根結點爲黑色。 * 3. 每個葉結點(實際上就是NULL指針)都是黑色的。 * 4. 如果一個結點是紅色的,那麼它的周邊3個節點都是黑色的。 * 5. 對於每個結點,從該結點到其所有子孫葉結點的路徑中所包含的黑色結點個數都一樣。 */ #include <stdio.h> #include <stdlib.h> #include "red_black.h" static red_black_t* rbt_rebalance(red_black_t *root, red_black_t *node); static red_black_t* rbt_rotate_right(red_black_t *root, red_black_t *node); static red_black_t* rbt_rotate_left(red_black_t *root, red_black_t *node); static red_black_t* rbt_delete_node(red_black_t *root, red_black_t *node); static int rbt_height(red_black_t *root); int init_rbt(red_black_t **root, int value) { if((*root = (red_black_t *)malloc(sizeof(red_black_t))) == NULL) { return -1; } (*root)->data = value; (*root)->color = BLACK; (*root)->parent = NULL; (*root)->left = NULL; (*root)->right = NULL; return 0; } void delete_rbt(red_black_t *root) { if(root) { delete_rbt(root->left); delete_rbt(root->right); free(root); } } /* * 插入操作:解決的是 紅-紅 問題 */ red_black_t* rbt_insert(red_black_t *root, int value) { red_black_t *node = (red_black_t *)malloc(sizeof(red_black_t)); red_black_t *parent; red_black_t *cur; if(node) { node->data = value; node->color = RED; node->parent = NULL; node->left = NULL; node->right = NULL; /* find parent node */ cur = root; parent = root; while(cur) { parent = cur; if(cur->data > value) { cur = cur->left; } else if(cur->data < value) { cur = cur->right; } else { return root; } } /* insert node */ node->parent = parent; if(parent) { if(parent->data > value) { parent->left = node; } else { parent->right = node; } } else { root = node; } root = rbt_rebalance(root, node); } return root; } /* * 1. 紅黑樹的插入和普通搜索二叉樹(Binary Search Tree)的插入一樣, * 只是在插入完以後,將新插入的節點標記爲紅色,然後從該節點開始,向上進行調整顏色。 * 2. 向上調整顏色進行旋轉時,旋轉的原則是儘量用1次或者最多2次旋轉完成, * 並且旋轉操作不能影響該層以下層次的節點,只能影響其父節點, * 然後將其父節點(或者叔節點、兄弟節點)作爲新的要調整顏色節點,繼續向上遞推調整。 * 3. 調整完後注意檢查根的顏色是否還是黑色。 */ static red_black_t* rbt_rebalance(red_black_t *root, red_black_t *node) { red_black_t *parent = NULL; red_black_t *uncle = NULL; red_black_t *ancestor = NULL; red_black_t *tmp = NULL; while(((parent=node->parent) != NULL) && (parent->color == RED)) { ancestor = parent->parent; /* parent 爲紅色, ancestor 一定爲黑色 */ if(parent == ancestor->left) { uncle = ancestor->right; if(uncle && uncle->color == RED) { /* parent 和 uncle 均爲紅色, 只需修改顏色 */ uncle->color = BLACK; parent->color = BLACK; ancestor->color = RED; node = ancestor; } else { /* 旋轉 */ if(parent->right == node) { /* 先左旋 */ /*----------------------------------------------------------- | bast bast | / / / / | rprt buce ==> rnode buce | / / / / | ba rnode rprt bc | / / / / | bb bc ba bb -----------------------------------------------------------*/ root = rbt_rotate_left(root, parent); tmp = parent; parent = node; node = tmp; } /*----------------------------------------------------------- | bast rprt bprt | / / / / / / | rprt buce ==> rnode bast ==> rnode rast | / / / / / / / / / / | rnode bc ba bb bc buce ba bb bc buce | / / | ba bb -----------------------------------------------------------*/ ancestor->color = RED; parent->color = BLACK; root = rbt_rotate_right(root, ancestor); } } else { /* 思路與 if 一樣 */ uncle = ancestor->left; if(uncle && uncle->color == RED) { /* parent 和 uncle 均爲紅色, 只需修改顏色 */ uncle->color = BLACK; parent->color = BLACK; ancestor->color = RED; node = ancestor; } else { /* 旋轉 */ if(parent->left == node) { /* 先左旋 */ /*----------------------------------------------------------- | bast bast | / / / / | buce rprt ==> buce rnode | / / / / | rnode bc ba rprt | / / / / | ba bb bb bc -----------------------------------------------------------*/ root = rbt_rotate_right(root, parent); tmp = parent; parent = node; node = tmp; } /*----------------------------------------------------------- | bast rprt bprt | / / / / / / | buce rprt ==> bast rnode ==> rast rnode | / / / / / / / / / / | ba rnode buce ba bb bc buce ba bb bc | / / | bb bc -----------------------------------------------------------*/ ancestor->color = RED; parent->color = BLACK; root = rbt_rotate_left(root, ancestor); } } } /* 上述過程有可能修改了 root 節點 */ root->color = BLACK; return root; } int rbt_delete(red_black_t **root, int value) { red_black_t *tmp; if((tmp=rbt_search(*root, value)) != NULL) { *root = rbt_delete_node(*root, tmp); } return 0; } /* * 刪除操作:解決的是 黑-黑 問題 * * * 刪除操作思路來自 二叉排序樹 * 刪除的節點都表示成實際要刪除的中序遍歷的後繼節點 * 那麼要刪除的節點的左子樹一定爲空, 由紅黑樹高度可知: * 如果刪除的節點爲紅色,那麼它必爲葉子節點 * 如果刪除的節點爲黑色, 刪除的節點要麼有一個右孩子,要麼爲葉子節點. */ static red_black_t* rbt_delete_node(red_black_t *root, red_black_t *node) { red_black_t *tmp = NULL; if(node->right == NULL) { /* 要刪除的節點只有左孩子或者沒有孩子 */ if(node->parent == NULL) { /* 刪除根節點 */ root = node->left; if(root) { root->color = BLACK; } } else if(node->parent->left == node) { node->parent->left = node->left; } else { node->parent->right = node->left; } /* 更新孩子父親 */ if(node->left) { node->left->parent = node->parent; } tmp = node->left; } else { /* 找到 root->right 的最左兒子代替 root, 換成刪除葉子節點或只有右孩子的節點 tmp */ tmp = node->right; while(tmp->left) { tmp = tmp->left; } node->data = tmp->data; /* 將要刪除的節點賦給 node */ node = tmp; if(node->parent->left == node) { node->parent->left = node->right; } else { node->parent->right = node->right; } if(node->right) { /* 右子樹非空 */ node->right->parent = node->parent; } tmp = node->right; } if(node->color == BLACK && tmp) { /* 刪除節點的顏色爲黑色且子樹不爲空時調整 */ root = rbt_rebalance(root, tmp); } free(node); return root; } /*----------------------------------------------------------- | node tmp | / / / / | tmp y ==> a node | / / / / | a b b y -----------------------------------------------------------*/ /* 只旋轉, 不改變顏色 */ static red_black_t* rbt_rotate_right(red_black_t *root, red_black_t *node) { red_black_t *tmp = node->left; if((tmp->parent=node->parent) == NULL) { root = tmp; } else { /* 修改 node 的 parent 節點的孩子指針 */ if(node->parent->left == node) { node->parent->left = tmp; } else { node->parent->right = tmp; } } node->parent = tmp; node->left = tmp->right; if(tmp->right) { tmp->right->parent = node; } tmp->right = node; return root; } /*----------------------------------------------------------- | node tmp | / / ==> / / | a tmp node y | / / / / | b y a b -----------------------------------------------------------*/ /* 只旋轉, 不改變顏色 */ static red_black_t* rbt_rotate_left(red_black_t *root, red_black_t *node) { red_black_t *tmp = node->right; if((tmp->parent=node->parent) == NULL) { root = tmp; } else { /* 修改 node 的 parent 節點的孩子指針 */ if(node->parent->left == node) { node->parent->left = tmp; } else { node->parent->right = tmp; } } node->parent = tmp; node->right = tmp->left; if(tmp->left) { tmp->left->parent = node; } tmp->left = node; return root; } void rbt_print_preorder(red_black_t *root) { if(root) { printf("%d [color: %s] ", root->data, (root->color == RED ? "RED" : "BLACK")); if(root->parent) { printf("[parent: %d] ", root->parent->data); } if(root->left) { printf("[left: %d] ", root->left->data); } if(root->right) { printf("[right: %d] ", root->right->data); } printf("/n"); rbt_print_preorder(root->left); rbt_print_preorder(root->right); } } red_black_t* rbt_search(red_black_t *root, int value) { red_black_t *cur = root; while(cur) { if(cur->data == value) { break; } else if(cur->data > value) { cur = cur->left; } else { cur = cur->right; } } return cur; } /* * 高度是指黑節點個數 */ int rbt_get_height(red_black_t *root) { int ret = 0; if(root) { ret = rbt_height(root); } return ret; } int rbt_height(red_black_t *root) { int ret = 1; /* 每個葉結點(實際上就是NULL指針)都是黑色的 */ int left = 0; int right = 0; if(root) { left = rbt_height(root->left); right = rbt_height(root->right); ret = (left >= right ? left : right) + 1; if(root->color == RED) { ret--; } } return ret; } void rbt_test_app(void) { int s, v; red_black_t *root = NULL; init_rbt(&root, 19); while(1) { printf("/n******************************/n"); printf("0: exit/n"); printf("1: print/n"); printf("2: find/n"); printf("3: depth/n"); printf("4: insert/n"); printf("5: delete/n"); printf("******************************/n"); printf("select: "); scanf("%d", &s); if(s == 0) { delete_rbt(root); return; } else if(s == 1) { rbt_print_preorder(root); } else if(s == 2 || s == 4 || s == 5) { printf("value: "); scanf("%d", &v); if(rbt_search(root, v) == NULL) { if(s == 4) { root = rbt_insert(root, v); } else if(s == 5) { printf("not exists fail delete/n"); } else { printf("not exists/n"); } } else { if(s == 5) { if(!rbt_delete(&root, v)) { printf("deleted/n"); } else { printf("fail delete/n"); } } else { printf("already exists/n"); } } } else if(s == 3) { printf("height: %d/n", rbt_height(root)); } } }
pt-osc原理探索及其觸發器的深入分析 > 作者:莫善,某互聯網公司高級 DBA。 > > 愛可生開源社區出品,原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。 > > 本文約 6000 字,預計閱讀需要 20 分鐘。 背景 自工
這個其實是一個特別高頻的面試題,松哥也一直很想和大家仔細來聊一聊這個話題,網上關於這塊的文章很多,但是我一直覺得要把這個問題講清楚還有點難度,今天我來試一試,看能不能和小夥伴們把這個問題梳理清楚,當然,如果小夥伴們覺得看文章不過癮,松哥也有
分享8個開箱即用的API,方便日常處理集合。 1. 快速過濾空值:Stream.ofNullable 該方法是在 Java 9 中引入的,有助於過濾集合中的所有空值,從而可能使我們避免空指針異常。 在下面的示例中,有一個包含 null 的L
一、背景 在日常部門OpsReview過程中,部門內多次遇到應用容器所在的宿主機磁盤繁忙導致的接口響應緩慢,TP99增高等影響服務性能的問題,其中比較有效的解決方案是開啓日誌的異步打印,可以有效避免同步日誌打印在磁盤IO高起的情況下拖慢業
本文分享自華爲雲社區《【MySQL技術專欄】MySQL8.0直方圖介紹》,作者:GaussDB 數據庫。 背景 數據庫查詢優化器負責將SQL查詢轉換爲儘可能高效的執行計劃,但因爲數據環境不斷變化導致優化器對查詢數據瞭解的不夠充足,可能無法
每篇一句 大魔王張怡寧:女兒,這堆金牌你拿去玩吧,但我的銀牌不能給你玩。你要想玩銀牌就去找你王浩叔叔吧,他那銀牌多 前言 爲了講述好Spring MVC最爲複雜的數據綁定這塊,我前面可謂是做足了功課,對此部分知識此處給小夥伴留一個學
作者:vivo 互聯網數據庫團隊- Qiu Xinbo 本文主要通過圖示介紹了用主鍵進行分片查詢的過程,介紹了主鍵分頁查詢存在SQL性能問題,如何去創建高效的索引去優化主鍵分頁查詢的SQL性能問題 對於數據分佈不均
JSON簡介: JSON(Java Script Object Notation)是一種輕量級的數據交換格式,通常用於在不同系統之間傳輸數據。它基於 JavaScript 對象語法,但已成爲一種獨立於語言的格式。JSON 數據以鍵值對的形式
本文分享自華爲雲社區《一文徹底喫透MyBatis源碼!!》,作者:冰 河。 寫在前面 隨着互聯網的發展,越來越多的公司摒棄了Hibernate,而選擇擁抱了MyBatis。而且,很多大廠在面試的時候喜歡問MyBatis底層的原理和源碼實現
DevExpress VCL是DevExpress公司旗下最老牌的用戶界面套包,所包含的控件有:數據錄入、圖表、數據分析、導航、佈局等。該控件能幫助您創建優異的用戶體驗,提供高影響力的業務解決方案,並利用您現有的VCL技能爲未來構建下一代應
DevExtreme擁有高性能的HTML5 / JavaScript小部件集合*使您可以利用現代Web開發堆棧*包括React*Angular*ASP.NET Core*jQuery*Knockout等*構建交互式的Web應用程序。從Ang
背景 這兩年來大模型及其熱門,不僅各大廠家的模型層出不窮,各類RGA、Agent應用也花樣繁多。這也帶火了一批基礎設施,比如Langchain、向量數據庫(也叫矢量數據庫-Vector Database)等。現在市場上的向量庫種類特別繁多
如何在數據安全與合規的前提下,高效地追蹤海外多媒體平臺的投放流量,有效歸因分析投放效果,持續優化企業在海外媒體的一系列營銷動作? 針對企業客戶的這一需求,神策數據從專業性和效率最佳兩個角度綜合考慮,接入多家第三方 MMP(Mobile
本文分享自華爲雲社區《【昇騰開發全流程】AscendCL開發板模型推理》,作者:沉迷sk。 前言 學會如何安裝配置華爲雲ModelArts、開發板Atlas 200I DK A2。 並打通一個Ascend910訓練到Ascend310推理
大家好,我是每天分享AI應用的螢火君! 今天繼續給大家分享ComfyUI的入門必備技能:ControlNet。 ControlNet 提供了十幾種生成圖片的控制方式,有的可以控制畫面的結構,有的可以控制人物的姿勢,還有的可以控制圖片的畫