C++色彩博弈的史詩:紅黑樹

文章目錄

  • 1.紅黑樹的概念
  • 2.紅黑樹的結構
  • 3.紅黑樹的插入
  • 4.紅黑樹的刪除
  • 5.紅黑樹與AVL樹的比較
  • 6.紅黑樹的驗證
  • 希望讀者們多多三連支持
  • 小編會繼續更新
  • 你們的鼓勵就是我前進的動力!

紅黑樹是一種自平衡二叉查找樹,每個節點都帶有顏色屬性,顏色或為紅色或為黑色,可以理解為 AVL 樹的進階版,建議系統學習完 AVL 樹再來看本篇博客

傳送門:C++漫步結構與平衡的殿堂:AVL樹

1.紅黑樹的概念

在這里插入圖片描述

紅黑樹,是一種二叉搜索樹,但在每個結點上增加一個存儲位表示結點的顏色,可以是 RedBlack。 通過對任何一條從根到葉子的路徑上各個結點著色方式的限制,紅黑樹確保最長路徑的節點數量不超過最短路徑節點數量的兩倍(剛好兩倍是可以的),因而是接近平衡的

一個合格的紅黑樹需要滿足以下條件:

  • 每個結點不是紅色就是黑色
  • 根節點是黑色的
  • 如果一個節點是紅色的,則它的兩個孩子結點必須是黑色的,任何路徑都沒有連續的紅色節點,也就是說可以有連續的黑色節點,但不可能一顆紅黑樹全是黑色節點
  • 對于每個結點,從該結點到其所有后代葉結點的簡單路徑上,均包含相同數目的黑色節點
  • 每個葉子結點都是黑色的(此處的葉子結點指的是空結點)

為什么滿足上面的性質,紅黑樹就能保證:其最長路徑中節點個數不會超過最短路徑節點個數的兩倍?

最短路徑就是僅由黑色節點構成的路徑。因為如果路徑中插入紅色節點,會使路徑變長,而全黑路徑不包含額外紅色節點,所以是最短的

最長路徑是紅黑交替出現的路徑。即每一個黑色節點后面都跟著一個紅色節點(但紅色節點后不能再有紅色節點)

設最短路徑的黑色節點數量為 n ,由于所有路徑黑色節點數量相同,最長路徑的黑色節點數量也為 n ,那么最長路徑由于紅黑交替的節點總數最多為 2n 。所以,最長路徑的節點個數不會超過最短路徑節點個數的兩倍

2.紅黑樹的結構

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

在節點的定義中,為什么要將節點的默認顏色給成紅色的?

紅黑樹的性質要求從根節點到每個葉子節點的路徑上黑色節點數量相同。將新節點設為紅色,在插入過程中,如果其父節點是黑色,那么插入紅色節點不會影響任何路徑上黑色節點的數量,也就不需要對樹進行調整來滿足紅黑樹的性質,從而減少了調整的可能性,提高了插入操作的效率

如果新節點是黑色,那么插入后可能會導致某個路徑上的黑色節點數量增加,這會引發更復雜的 “雙黑” 問題,即刪除或插入操作后出現一個節點需要同時承擔兩個黑色節點的情況,處理起來相對復雜。而默認新節點為紅色,出現的問題主要是紅節點沖突,處理相對簡單,以下的插入會詳細解釋原因

3.紅黑樹的插入

typedef RBTreeNode<K, V> Node;
bool Insert(const pair<K, V>& kv)
{//根節點為空的情況if (_root == nullptr){_root = new Node(kv);_root->_col = BLACK;return true;}//查找插入節點位置Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else{return false;}}//鏈接插入節點與紅黑樹cur = new Node(kv);cur->_col = RED;if (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = grandfather->_right;// u存在且為紅if (uncle && uncle->_col == RED){// 變色parent->_col = uncle->_col = BLACK;grandfather->_col = RED;// 繼續向上處理cur = grandfather;parent = cur->_parent;}else // u不存在 或 存在且為黑{if (cur == parent->_left){//     g//   p// cRotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{//     g//   p//		cRotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else // parent == grandfather->_right{Node* uncle = grandfather->_left;// u存在且為紅if (uncle && uncle->_col == RED){// 變色parent->_col = uncle->_col = BLACK;grandfather->_col = RED;// 繼續向上處理cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_right){// g//	  p//       cRotateL(grandfather);grandfather->_col = RED;parent->_col = BLACK;}else{// g//	  p// cRotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return true;
}

對于插入的節點,可能會遇到三種情況:

🚩uncle存在且為紅
在這里插入圖片描述

我們定義插入節點為 cur,其父節點為 parent,父節點的兄弟節點為 uncle,父節點的父節點為 grandfather

當新插入節點的雙親節點顏色為紅色時,就違反了不能有連在一起的紅色節點,想要盡可能不破壞紅黑樹的平衡結構的情況下正常插入,那么通過變色解決是最好的

請添加圖片描述

不能連續出現紅色節點,還要保持每條路徑的黑色節點相同,可以將 parentuncle 變黑,grandfather 變紅解決

在這里插入圖片描述

發現處理完之后,在子樹上是保持平衡的,但是 grandfather 又出現了連續紅色節點,這是其中一種情況,總共有三種情況:

  1. grandfather 沒有父親,就是根,直接變黑就好了
  2. grandfather 有父親,父親是黑色,直接結束
  3. grandfather 有父親,父親是紅色,重復上述操作

很明顯示例就是第三種

🚩uncle不存在

在這里插入圖片描述

uncle 不存在的時候,發現通過變色已經不能解決問題了,這個時候就要旋轉調整結構了,根據 cur 的位置判斷進行單旋還是雙旋

在這里插入圖片描述

然后根據結構性質進行變色即可

🚩uncle存在且為黑
在這里插入圖片描述

uncle 存在且為黑的時候,情況和 uncle 不存在是一樣的

🔥值得注意的是: AVL 樹旋轉可以根據平衡因子為 2 的相對位置來判斷是要單旋還是雙旋,紅黑樹根據 grandfatherparentcur 的相對位置來判斷,也就是要多畫圖

4.紅黑樹的刪除

紅黑樹的刪除本節不做講解,有興趣可參考:《算法導論》或者《STL源碼剖析》

傳送門:博客園相關講解

5.紅黑樹與AVL樹的比較

可是紅黑樹的時間復雜度比AVL樹更高啊,為什么反而用的更多?

紅黑樹AVL樹
最長路徑不超過最短路徑的2倍高度差不超過1
10億個值10億個值
2*logN->60logN->30

可以看到數據,性能處理上大概相差兩倍,但是要知道 CPU 的性能是很強大的,每秒能處理十幾億的數據,這點差距根本不足為懼,而且紅黑樹和 AVL 樹是處于同一量級的,但是 AVL 樹的插入刪除需要大量的旋轉,控制嚴格平衡的代價太大,因此使用紅黑樹更多

6.紅黑樹的驗證

🚩檢查是否有連續紅色節點

bool CheckColour(Node* root, int blacknum, int benchmark)
{if (root == nullptr){if (blacknum != benchmark)return false;return true;}if (root->_col == BLACK){++blacknum;}if (root->_col == RED && root->_parent && root->_parent->_col == RED){cout << root->_kv.first << "出現連續紅色節點" << endl;return false;}return CheckColour(root->_left, blacknum, benchmark)&& CheckColour(root->_right, blacknum, benchmark);
}

🚩檢查是否平衡

bool IsBalance()
{return IsBalance(_root);
}bool IsBalance(Node* root)
{if (root == nullptr)return true;if (root->_col != BLACK){return false;}// 基準值int benchmark = 0;Node* cur = _root;while (cur){if (cur->_col == BLACK)++benchmark;cur = cur->_left;}return CheckColour(root, 0, benchmark);
}int Height()
{return Height(_root);
}int Height(Node* root)
{if (root == nullptr)return 0;int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

希望讀者們多多三連支持

小編會繼續更新

你們的鼓勵就是我前進的動力!

請添加圖片描述

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

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

相關文章

基于STM32、HAL庫的CH342F USB轉UART收發器 驅動程序設計

一、簡介: CH342F是一款USB轉串口芯片,由南京沁恒電子(WCH)生產,具有以下特點: 支持USB轉UART、IrDA紅外或SPI接口 內置時鐘,無需外部晶振 支持5V和3.3V電源電壓 最高支持3Mbps波特率 支持常用的MODEM聯絡信號 內置EEPROM,可配置設備VID/PID/序列號等 二、硬件接口: C…

項目功能-圖片清理(上)

一、圖片存儲介紹 在實際開發中&#xff0c;我們會有很多處理不同功能的服務器。例如&#xff1a; 應用服務器&#xff1a;負責部署我們的應用 數據庫服務器&#xff1a;運行我們的數據庫 文件服務器&#xff1a;負責存儲用戶上傳文件的服務器 分服務器處理的目的是讓服務…

創建三個網絡,分別使用RIP、OSPF、靜態,并每個網絡10個電腦。使用DHCP分配IP

DHCP 自動分配IP&#xff0c;集中管理&#xff0c;提高效率 在路由器中設置 Router>en Router#conf t Router(config)#ip dhcp pool ip30 //創建DHCP地址池 Router(dhcp-config)#network 192.168.30.0 255.255.255.0 // 配置網絡地址和子網掩碼 Router(dhcp-config)#defa…

如何使用 WMIC 命令在 Windows 11 或 10 上卸載軟件

如果您正在尋找一個命令提示符或 PowerShell 命令來卸載 Windows 應用程序,那么使用 wmic(Windows Management Instrumentation Command-line)是一種強大的技術,尤其是在處理難以卸載的程序或自動化卸載過程時。在本教程中,我們將學習如何使用 wmic 來卸載軟件。 先決條件…

FEKO許可證的安全與合規性

在電磁仿真領域&#xff0c;FEKO軟件因其出類拔萃的性能和廣泛的應用場景&#xff0c;贏得了全球用戶的廣泛贊譽。但在這背后&#xff0c;是什么讓FEKO在眾多競爭者中脫穎而出&#xff1f;答案是其許可證的安全與合規性。它們不僅為用戶提供了堅固的保障&#xff0c;更確保了用…

ESP32開發入門(九):HTTP服務器開發實踐

一、HTTP服務器基礎 1.1 什么是HTTP服務器&#xff1f; HTTP服務器是能夠處理HTTP請求并返回響應的網絡服務程序。在物聯網應用中&#xff0c;ESP32可以作為輕量級HTTP服務器&#xff0c;直接接收來自客戶端(如瀏覽器、手機APP)的請求。 1.2 ESP32作為HTTP服務器的特點 輕量…

《棒球百科》MLB棒球公益課·棒球1號位

MLB&#xff08;美國職業棒球大聯盟&#xff09;的棒球公益課通過推廣棒球運動、普及體育教育&#xff0c;對全球多個地區產生了多層次的影響&#xff1a; 1. 體育文化推廣 非傳統棒球地區的普及&#xff1a;在棒球基礎較弱的地區&#xff08;如中國、歐洲部分國家&#xff09…

Baumer工業相機堡盟工業相機的工業視覺是否可以在室外可以做視覺檢測項目

Baumer工業相機堡盟工業相機的工業視覺是否可以在室外可以做視覺檢測項目 Baumer工業相機?視覺檢測項目為什么偏愛“室內環境”&#xff1f;?工業視覺中為什么傾向于室內環境**保障人員與設備安全**&#xff1a;室內環境可以提供更好的安全保障&#xff0c;避免檢測設備和人員…

1. 使用 IntelliJ IDEA 創建 React 項目:創建 React 項目界面詳解;配置 Yarn 為包管理器

1. 使用 IntelliJ IDEA 創建 React 項目&#xff1a;創建 React 項目界面詳解&#xff1b;配置 Yarn 為包管理器 &#x1f9e9; 使用 IntelliJ IDEA 創建 React 項目&#xff08;附 Yarn 配置與 Vite 建議&#xff09;&#x1f4f7; 創建 React 項目界面詳解1?? Name&#xf…

C++GO語言微服務之用戶信息處理②

目錄 01 03-獲取用戶信息-上 02 04-獲取用戶信息-下 03 05-更新用戶名實現 01 06-中間件簡介和中間件類型 02 07-中間件測試和模型分析 03 08-中間件測試案例和小結 04 09-項目使用中間件 01 03-獲取用戶信息-上 ## Cookie操作 ### 設置Cookie go func (c *Context) …

QMK鍵盤固件開發全解析:QMK 固件開發的最新架構和規范(2025最新版)

QMK鍵盤固件開發全解析:QMK 固件開發的最新架構和規范(2025最新版) ?? 前言概述 QMK(Quantum Mechanical Keyboard)作為目前開源鍵盤固件領域的"扛把子",憑借其強大的功能和活躍的社區支持,已經成為眾多DIY鍵盤愛好者的首選開發框架。無論是入門級玩家還是資…

極狐GitLab 容器鏡像倉庫功能介紹

極狐GitLab 是 GitLab 在中國的發行版&#xff0c;關于中文參考文檔和資料有&#xff1a; 極狐GitLab 中文文檔極狐GitLab 中文論壇極狐GitLab 官網 極狐GitLab 容器鏡像庫 (BASIC ALL) 您可以使用集成的容器鏡像庫&#xff0c;來存儲每個極狐GitLab 項目的容器鏡像。 要為您…

Umi+React+Xrender+Hsf項目開發總結

一、菜單路由配置 1.umirc.ts 中的路由配置 .umirc.ts 文件是 UmiJS 框架中的一個配置文件&#xff0c;用于配置應用的全局設置&#xff0c;包括但不限于路由、插件、樣式等。 import { defineConfig } from umi; import config from ./def/config;export default defineCon…

【運維】基于Python打造分布式系統日志聚合與分析利器

《Python OpenCV從菜鳥到高手》帶你進入圖像處理與計算機視覺的大門! 解鎖Python編程的無限可能:《奇妙的Python》帶你漫游代碼世界 在分布式系統中,日志數據分散在多個節點,管理和分析變得復雜。本文詳細介紹如何基于Python開發一個日志聚合與分析工具,結合Logstash和F…

Python實戰:海量獲取京東商品信息

在數據驅動的商業時代&#xff0c;數據就是最寶貴的資源。對于電商從業者、市場分析師而言&#xff0c;從京東這類大型電商平臺獲取商品信息&#xff0c;能夠為市場調研、競品分析、銷售策略制定提供重要依據。今天&#xff0c;就來分享如何用Python實現京東商品信息的海量獲取…

聊一聊常見的超時問題:timeout

大家好&#xff0c;我是G探險者&#xff01; 在日常開發中&#xff0c;“超時&#xff08;Timeout&#xff09;”類錯誤是開發者們經常遇到的問題。無論是調用第三方服務、訪問數據庫&#xff0c;還是并發任務處理&#xff0c;都可能因超時而導致請求失敗或系統異常。 本文將系…

創建型模式:工廠方法(Factory Method)模式

一、簡介 工廠方法(Factory Method)模式是一種創建型設計模式,它定義了一個創建對象的接口,但讓子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到其子類。在 C# 中,工廠方法模式提供了一種更靈活的對象創建方式,將對象的創建和使用分離,提高了代碼的可維護性和…

外網訪問內網海康威視監控視頻的方案:WebRTC + Coturn 搭建

外網訪問內網海康威視監控視頻的方案&#xff1a;WebRTC Coturn 需求背景 在倉庫中有海康威視的監控攝像頭&#xff0c;內網中是可以直接訪問到監控攝像的畫面&#xff0c;由于項目的需求&#xff0c;需要在外網中也能看到監控畫面。 實現這個功能的意義在于遠程操控設備的…

Redis 8.0正式發布,再次開源為哪般?

Redis 8.0 已經于 2025 年 5 月 1 日正式發布&#xff0c;除了一些新功能和性能改進之外&#xff0c;一個非常重要的改變就是新增了開源的 AGPLv3 協議支持&#xff0c;再次回歸開源社區。 為什么說再次呢&#xff1f;這個需要從 2024 年 3 月份 Redis 7.4 說起&#xff0c;因為…

382_C++_在用戶會話結束時,檢查是否有其他會話仍然來自同一個客戶端 IP 地址,沒有連接狀態設置為斷開,否則為連接

之前出現的問題:重啟管理機,工作機上面熱備連接狀態顯示未連接 (此時是有一個工作機連接管理機的),所以正常應該是連接狀態解決:根因分析: 重啟管理機后,管理機給過來的cookie是空的,導致工作機同時存在兩個管理機的session,在其中一個超時后,調用回調函數通知會話斷開…