數據結構系列之紅黑樹


前言

紅黑樹是比較重要的一顆樹了,map和set的底層就是紅黑樹,一定要牢牢記住。


一、什么是紅黑樹

首先:紅黑樹仍然是一顆搜索二叉樹,但他引入了顏色這一概念,每個結點多一個存儲位來存儲顏色,它通過維護下面五條規則來保證,最長路徑不超過最短路徑的二倍。

1.每個結點不是黑顏色就是紅顏色
2.根節點是黑色
3.如果一個節點是紅色,則他存在的孩子節點是黑色,換句話說,任意一條路徑不存在連續的紅色節點。
4.對于每個節點,到所有NIL節點的路徑上,均含有相同數量的黑色節點。
5.每個NIL節點都是黑色的
為什么設計第五條規則?看圖:
在這里插入圖片描述
這五條規則里最重要的就是三和四,插入也要維護三和四。

為什么維護了這五條規則就能達到最長路徑不超過最短路徑的二倍呢?
最短路徑:全是黑色節點
最長路徑:一黑一紅,又因為黑色節點的數量相同,所以最長的路徑最多是最短路徑的二倍。

二、模擬

紅黑樹還是模擬插入過程,還是寫成K,V和三叉鏈結構

節點定義

enum class Color {RED,BLACK
};template<class K,class V>
struct RBTreeNode {RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;Color color;pair<K, V> _kv;RBTreeNode(const pair<K,V>& p):_left(nullptr),_right(nullptr),_parent(nullptr),color(Color::RED),_kv(p){}
};

這里有兩個注意的點:
1.這個枚舉是C++新搞出來的,和原來枚舉不同的就是不是全局的。
2.節點的默認顏色搞成紅色,如果搞成黑色,這一條路徑上的黑色節點加一,而其他所有路徑上的黑色數目就會相對較少,不好維護,所以違反第三條規則,維護第三條規則,這需要維護這一條和叔叔路徑上的。

搜索樹的邏輯插入:

bool insert(const pair<K, V>& p)
{if (_root == nullptr){_root = new Node(p);_root->color = Color::BLACK;return true;}else{Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_kv.first < p.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > p.first){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(p);if (parent->_kv.first < p.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//這之前都是搜索樹的邏輯//

調整顏色的邏輯:
在這里插入圖片描述

	while (parent && parent->color == Color::RED){Node* grandf = parent->_parent;if (grandf->_left == parent){Node* uncle = grandf->_right;//叔叔存在且為紅if (uncle && uncle->color == Color::RED){//判斷uncle->color = parent->color = Color::BLACK;grandf->color = Color::RED;//繼續判斷cur = grandf;parent = cur->_parent;}//叔叔不存在或者為黑else{//開旋if (parent->_left == cur){RotateRight(grandf);parent->color = Color::BLACK;grandf->color = Color::RED;}else{//parent->right  是cur,grandf的左邊是parentRotateLeft(parent);RotateRight(grandf);cur->color = Color::BLACK;grandf->color = Color::RED;}}}//祖父的右邊是父親else{Node* uncle = grandf->_left;//uncle不存在 或者uncle為黑//uncle為紅if (uncle && uncle->color == Color::RED){parent->color = uncle->color = Color::BLACK;grandf->color = Color::RED;cur = grandf;parent = cur->_parent;}//uncle為黑或者不存在else{//旋轉//   grandf//uncle                parent//curif (cur == parent->_right){RotateLeft(grandf);parent->color = Color::BLACK;grandf->color = Color::RED;}else{RotateRight(parent);RotateLeft(grandf);cur->color = Color::BLACK;grandf->color = Color::RED;}}}}_root->color = Color::BLACK;return true;
}

其實還可以,順一順思路:
當父親存在并且父親的顏色是紅就更新
先判斷祖父的左邊是父親還是右邊,需要根據這個旋轉
然后判斷uncle,也就是祖父的另一個孩子,如果uncle為紅,和parent一起改顏色,往上更新。
如果為黑或者不存在,要旋轉,直線型單旋,折線型雙旋,注意控制顏色,旋轉完的父親一定為黑,左右兩個孩子都為紅。

三、驗證是否正確

1.驗證是否為二叉搜索樹,走一個中序遍歷就可以,有序即為二叉搜索樹。

2.驗證是否紅黑樹滿足條件:
主要是看三和四,三:看有無連續紅色節點,利用父親來判斷,
四:看黑色節點的數量,可以先求出一條路徑的數量,然后再去遞歸所有路徑進行比較。

bool CheckColor(Node* node,int blacknum,int basic)
{
if (node == nullptr)
{if (blacknum != basic){cout << "違背了第四條規則" << endl;return false;}return true;
}
if (node->color == Color::BLACK)
{blacknum++;
}
//檢查孩子很麻煩,檢查父親
if (node->color == Color::RED && node->_parent && node->_parent->color == Color::RED)
{cout << "出現了連續的紅色結點" << endl;return false;
}
return CheckColor(node->_left,blacknum,basic) && CheckColor(node->_right, blacknum, basic);}
bool _IsBalance(Node* node)
{if (node == nullptr) return true;if (node->color != Color::BLACK){//根節點是黑色return false;//第二條}int basic = 0;Node* cur = node;while (cur){if (cur->color == Color::BLACK){basic++;}cur = cur->_left;}return CheckColor(node,0,basic);
}

四、性能

代碼測試

int main()
{RBTree<int, int> rb;AVLTree<int, int> avl;srand(time(0));size_t N = 100000000;vector<int> v(N);for (size_t i = 0; i < N; ++i) v[i] = rand() + i;int begin1 = clock();for (size_t i = 0; i < N; ++i) {rb.insert({ v[i],v[i] });}int end1 = clock();int begin2 = clock();for (size_t i = 0; i < N; ++i){avl.insert({ v[i],v[i] });}int end2 = clock();if (rb.IsBalance() && avl.IsBalance()){cout << "插入" << N << "個數據" << "紅黑樹用時間" << end1 - begin1 << ' ' << "旋轉次數:" << rb.RotateCount;cout << endl;cout << "插入" << N << "個數據" << "AVL樹用時間" << end2 - begin2 << ' ' << "旋轉次數:" << avl.Rotatecount;}return 0;
}

在這里插入圖片描述

還可以去測試一下他們的高度,有序數據,隨機數據,查找的效率等等。
總體來說,紅黑樹是更優秀的,數據量越大紅黑樹的優勢就越明顯。

紅黑樹和AVL樹都是高效的平衡二叉樹,增刪改查的時間復雜度都是O(logN),紅黑樹不追求絕對平衡,其只需保證最長路徑不超過最短路徑的2倍,相對而言,降低了插入和旋轉的次數,所以在經常進行增刪的結構中性能比AVL樹更優,而且紅黑樹實現比較簡單,所以實際運用中紅黑樹更多。


五、完整代碼

個人gitee

總結

紅黑樹很重要!!!!一定要牢牢掌握。
接下來map和set還需要使用它。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/93040.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/93040.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/93040.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在OpenMP中,#pragma omp的使用

在OpenMP中&#xff0c;#pragma omp for 和 #pragma omp parallel for&#xff08;或 #pragma omp parallel num_threads(N)&#xff09;有本質區別&#xff0c;主要體現在 并行區域的創建 和 工作分配方式 上。以下是詳細對比&#xff1a;1. #pragma omp for 作用 僅分配循環迭…

停止“玩具式”試探:深入拆解ChatGPT Agent的技術棧與實戰避坑指南

摘要&#xff1a; 當許多人還在用ChatGPT寫周報、生成樣板代碼時&#xff0c;其底層的Agent化能力已經預示著一場深刻的開發范式變革。這不再是簡單的“AI輔助”&#xff0c;而是“人機協同”的雛形。本文旨在穿透表面的功能宣傳&#xff0c;從技術棧層面拆解Agent模式的實現基…

element-plus安裝以及使用

element-plus時為vue.js 3開發的組件庫。 在引入前需要做如下準備 安裝node.js https://blog.csdn.net/zlpzlpzyd/article/details/147704723 安裝vue的腳手架vue-cli https://blog.csdn.net/zlpzlpzyd/article/details/149647351 安裝element-plus github地址 https://git…

學習隨想錄-- web3學習入門計劃

#60 轉方向 web3 golang 以太坊應用 這是課表部分&#xff08;Golang以太坊方向&#xff09; Sheet b站up學習計劃 第一階段&#xff1a;基礎能力構建&#xff08;1-2 個月&#xff09; 學習目標 掌握 Golang 核心語法與以太坊底層基礎概念&#xff0c;建立開發知識框架。…

【RAG優化】PDF復雜表格解析問題分析

在構建檢索增強生成(RAG)應用時,PDF文檔無疑是最重要、也最普遍的知識來源之一。然而,PDF中潛藏著RAG系統的難點問題——復雜表格。這些表格富含高密度的結構化信息,對回答精準問題至關重要,但其復雜的視覺布局(多層表頭、合并單元格、跨頁表格等)常常讓標準的文本提取…

ReAct Agent(LangGraph實現)

文章目錄參考資料一 AI Agent二 ReAct三 LangGraph實現ReAct代理3.1 SerperAPI實時聯網搜索3.2 ReAct實現參考資料 entic RAG 架構的基本原理與應用入門 一 AI Agent AI Agent 整個過程是一個動態循環。Agent不斷從環境中學習&#xff0c;通過其行動影響環境&#xff0c;然后…

如何從0到1的建立組織級項目管理體系【現狀診斷】

今天我想給大家分享是“如何在企業中從0到1的去建立PMO的組織級項目管理體系。”的系列文章&#xff0c;這是我近幾年來一直在努力的嘗試去探索和實踐的過程&#xff0c;從0到1的過程。當我最開始去接手這樣一個場景的時候所需要做的第一件事情是診斷和差距分析。這是多年以來做…

網絡通信協議詳解:TCP協議 vs HTTP協議

在計算機網絡中&#xff0c;TCP&#xff08;傳輸控制協議&#xff09;和HTTP&#xff08;超文本傳輸協議&#xff09;是兩個核心協議&#xff0c;但它們的職責和層級完全不同。TCP是底層傳輸協議&#xff0c;負責數據的可靠傳輸&#xff1b;HTTP是應用層協議&#xff0c;定義了…

[Qt]QString隱式拷貝

引言在Qt框架中&#xff0c;QString 作為字符串處理的核心類&#xff0c;其高效的內存管理機制一直是開發者津津樂道的特性。這背后的關鍵便是 隱式共享&#xff08;Implicit Sharing&#xff09;&#xff0c;也稱為 寫時復制&#xff08;Copy-On-Write, COW&#xff09;。本文…

命令行創建 UV 環境及本地化實戰演示—— 基于《Python 多版本與開發環境治理架構設計》的最佳實踐

命令行創建 UV 環境及本地化實戰&#xff1a;基于架構設計的最佳實踐 Python 多版本環境治理理念驅動的系統架構設計&#xff1a;三維治理、四級隔離、五項自治 原則-CSDN博客 使用 Conda 工具鏈創建 UV 本地虛擬環境全記錄——基于《Python 多版本與開發環境治理架構設計》-CS…

跨域問題全解:從原理到實戰

在計算機網絡中&#xff0c;跨域&#xff08;Cross-Origin&#xff09; 指的是瀏覽器出于安全考慮&#xff0c;限制網頁腳本&#xff08;如 JavaScript&#xff09;向與當前頁面不同源&#xff08;Origin&#xff09; 的服務器發起請求的行為。這是由瀏覽器的同源策略&#xff…

(46)elasticsearch-華為云CCE無狀態負載部署

一、準備好elasticsearch鏡像并提前上傳到鏡像倉庫 此次準備的是elasticsearch:v7.10.2 二、開始部署 負載名稱:es-deployment 注意:內部配額太低會造成多次重啟 環境變量: #單節點啟動(實例pod可以多增加幾個) discovery.type single-node 三、添加svc 四、注意:…

HCLP--MGER綜合實驗

一、拓撲圖二、需求1、R5為ISP&#xff0c;只能進行IP地址配置&#xff0c;其所有地址均配為公有I地址; 2、R1和R5間使用PPP的PAP認證&#xff0c;R5為主認證方&#xff0c; R2與R5之間使用ppp的CHAP認證&#xff0c;R5為主認證方; R3與R5之間使用HDLc封裝; 3、R1、R2、R3構建一…

idea中無法刪除模塊,只能remove?

1.先對module右鍵想要刪除的module&#xff0c;選擇remove module&#xff08;這是idea為了避免誤操作&#xff09; 2.在remove module后&#xff0c;模塊并未從項目結構中刪除&#xff08;磁盤中也依舊存在&#xff09;&#xff0c;但再次右擊你會發現&#xff0c;出現了del…

青藤天睿RASP再次發威!捕獲E簽寶RCE 0day漏洞

在2025年HVV關鍵攻防節點上&#xff0c;攻擊隊對E簽寶電子合同服務發起的0day攻擊被青藤天睿RASP截獲。該漏洞可使攻擊者在未授權情況下實現服務器遠程代碼執行&#xff08;RCE&#xff09;&#xff0c;進而控制服務器&#xff0c;構成橫向滲透的關鍵跳板。>>>>漏洞…

Lua(字符串)

Lua字符串基礎Lua中的字符串是不可變序列&#xff0c;可以包含任意字節數據&#xff08;包括嵌入的\0&#xff09;。字符串可以用單引號、雙引號或長括號&#xff08;[[ ]]&#xff09;定義&#xff1a;str1 "Hello" str2 World str3 [[Multi-line string]]字符串…

大模型蒸餾(distillation)---從DeepseekR1-1.5B到Qwen-2.5-1.5B蒸餾

目錄 1.1 蒸餾目標 2 環境準備 2.1依賴庫安裝 2.2 硬件要求 2.3 模型與數據集下載 2.3.1 教師模型下載 2.3.2 學生模型下載 2.3.3 數據集準備或下載 3.過程日志 4. 模型加載與配置 4.1 加載教師模型 4.2 加載學生模型 4.3 數據預處理函數 4.4 數據收集器 4.5 定義…

通過redis_exporter監控redis cluster

環境說明&#xff1a; 現在有一套redis cluster&#xff0c;部署是3主機6實例架構部署。需要采集對應的指標&#xff0c;滿足異常監控告警&#xff0c;性能分析所需。 環境準備 以下環境需要提前部署完成。 redis cluser prometheus alertmanager grafna redis_exporter部署 我…

第二十天(正則表達式與功能實際運用)

在程序員一生的工作中&#xff0c;遇到的最多的數據就是字符串字符串里面很有可能有很多的不需要的信息我們需要從中間挑選出我們需要的如果循環去寫&#xff0c;比較簡單的時候問題不大規則多了&#xff0c;你的工作量會成倍上升的為了解決這個問題 ---- 正則表達式正則表達式…

0基礎法考隨手筆記 03(刑訴05 刑事證據與證明+06 強制措施)

1.如何區分書證和電子數據 書面材料是否為書證&#xff1f;→ 看內容是否直接源于案件事實&#xff08;不是 “記錄別人陳述” 的載體&#xff09;。 證據清單是否為證據&#xff1f;→ 看誰做的清單&#xff08;偵查人員做的勘查筆錄是證據&#xff0c;當事人做的目錄不是&…