C++-紅黑樹

1、紅黑樹的概念

????????紅黑樹,是一種二叉搜索樹,但在每個結點上增加一個存儲位表示結點的顏色,可以是Red或 Black。 通過對任何一條從根到葉子的路徑上各個結點著色方式的限制,紅黑樹確保沒有一條路 徑會比其他路徑長出倆倍,因而是接近平衡的。

紅黑樹圖像,如圖所示:

2、紅黑樹的性質

  1. 顏色屬性:每個節點不是紅色就是黑色

  2. 根節點屬性:根節點必須是黑色的

  3. 紅色節點屬性:如果一個節點是紅色的,則它的兩個子節點必須是黑色的(即不能有兩個連續的紅色節點)

  4. 黑色高度屬性:對于每個節點,從該節點到其所有后代葉節點的簡單路徑上,包含相同數目的黑色節點

  5. 葉子節點屬性:每個葉子節點(NIL節點,空節點)都是黑色的

????????這些性質保證了紅黑樹的關鍵特性:最長路徑不超過最短路徑的兩倍,從而保證了樹的平衡性。

3、紅黑樹的實現

1.節點結構定義

template<class T>
struct RBTreeNode {RBTreeNode<T>* _left;    // 左子節點RBTreeNode<T>* _right;   // 右子節點RBTreeNode<T>* _parent;  // 父節點T _kv;                   // 鍵值對數據Colour _col;             // 節點顏色(RED或BLACK)RBTreeNode(const T& kv):_left(nullptr), _right(nullptr), _parent(nullptr),_kv(kv), _col(RED) {}
};

????????節點包含左右子節點指針、父節點指針、存儲的數據以及顏色標記。新節點默認為紅色。

2. 插入操作 (Insert)

????????功能:向紅黑樹中插入一個新節點,并保持紅黑樹的性質。

步驟

  1. 如果樹為空,創建新節點作為根節點,并設為黑色

  2. 按照二叉搜索樹的規則找到插入位置

  3. 創建新節點(紅色)并插入到正確位置

  4. 檢查并修復紅黑樹性質:

    • 如果父節點是黑色,無需處理

    • 如果父節點是紅色,需要調整:

      • 情況1:叔叔節點是紅色 - 變色處理

      • 情況2:叔叔節點是黑色或不存在 - 旋轉處理

  5. 確保根節點始終為黑色

約定:cur為當前節點,p為父節點,g為祖父節點,u為叔叔節點

  • 情況一: cur為紅,p為紅,g為黑,u存在且為紅

cur和p均為紅,違反了性質三,此處能否將p直接改為黑?

????????解決方式:將p,u改為黑,g改為紅,然后把g當成cur,繼續向上調整。

  • 情況二: cur為紅,p為紅,g為黑,u不存在/u存在且為黑

p為g的左孩子,cur為p的左孩子,則進行右單旋轉;

相反, p為g的右孩子,cur為p的右孩子,則進行左單旋轉

p、g變色--p變黑,g變紅

  • 情況三: cur為紅,p為紅,g為黑,u不存在/u存在且為黑

p為g的左孩子,cur為p的右孩子,則針對p做左單旋轉;

相反, p為g的右孩子,cur為p的左孩子,則針對p做右單旋轉

則轉換成了情況2

針對每種情況進行相應的處理即可。

bool Insert(const T& 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;
}

3. 左旋操作 (RotateL)

????????功能:以parent節點為支點進行左旋。

操作

  1. 將cur的左子節點作為parent的右子節點

  2. 將parent作為cur的左子節點

  3. 更新各個節點的父指針

  4. 處理根節點情況

//左單旋
void RotateL(Node* parent)
{Node* cur = parent->_right;parent->_right = cur->_left;if (cur->_left){cur->_left->_parent = parent;}cur->_left = parent;Node* pparent = parent->_parent;parent->_parent = cur;if (pparent == nullptr){_root = cur;cur->_parent = nullptr;}else{if (pparent->_left == parent){pparent->_left = cur;}else if (pparent->_right == parent){pparent->_right = cur;}cur->_parent = pparent;}
}

4.右旋操作 (RotateR)

????????功能:以parent節點為支點進行右旋。

操作

  1. 將cur的右子節點作為parent的左子節點

  2. 將parent作為cur的右子節點

  3. 更新各個節點的父指針

  4. 處理根節點情況

//右單旋
void RotateR(Node* parent)
{Node* cur = parent->_left;parent->_left = cur->_right;if (cur->_right){cur->_right->_parent = parent;}Node* pparent = parent->_parent;cur->_right = parent;parent->_parent = cur;if (pparent == nullptr){_root = cur;cur->_parent = nullptr;}else{if (pparent->_left == parent){pparent->_left = cur;}else{pparent->_right = cur;}cur->_parent = pparent;}
}

5. 紅黑樹驗證 (IsBalance)

功能:驗證紅黑樹是否滿足以下性質:

  1. 每個節點要么是紅色,要么是黑色

  2. 根節點是黑色

  3. 每個葉子節點(NIL節點)是黑色

  4. 不能有兩個連續的紅色節點

  5. 從任一節點到其每個葉子的所有路徑都包含相同數目的黑色節點

實現

  1. IsBalance()是公開接口,調用IsBalance(_root)

  2. IsBalance(Node* root)驗證根節點是否為黑色

  3. CheckColour()遞歸檢查:

    • 計算每條路徑的黑色節點數是否一致

    • 檢查是否有連續的紅色節點

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

4、紅黑樹與AVL樹的比較

特性紅黑樹AVL樹
平衡標準近似平衡(最長路徑≤2倍最短)嚴格平衡(高度差≤1)
查詢效率O(log n)O(log n)
插入/刪除效率相對較高(旋轉次數少)相對較低(旋轉次數多)
實現復雜度中等較高
適用場景頻繁插入刪除的場景查詢為主、很少修改的場景

5、 紅黑樹的應用

  1. C++ STL:map、set、multimap、multiset

  2. Java集合框架:TreeMap、TreeSet

  3. Linux內核:進程調度、內存管理等

  4. 其他:數據庫索引、文件系統等

6、 總結

????????紅黑樹是一種高效的平衡二叉搜索樹,它通過顏色標記和旋轉操作維持樹的近似平衡。相比于AVL樹,紅黑樹在插入和刪除操作上更為高效,適合需要頻繁修改的場景。理解紅黑樹的原理和實現,對于深入掌握STL容器和許多系統級的數據結構都有重要意義。

?????????紅黑樹的設計體現了計算機科學中典型的時空權衡思想:通過放寬平衡條件來減少維護平衡的開銷,同時仍能保證較好的性能。這種思想在許多算法和數據結構中都有體現,值得深入理解和掌握。

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

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

相關文章

在Python中避免使用`None`表示特殊情況:函數返回值與異常處理的最佳實踐 (Effective Python 第20條)

在Python編程中&#xff0c;函數的設計與實現直接影響代碼的可讀性、可維護性和健壯性。一個常見的問題是如何處理函數的返回值&#xff0c;尤其是在需要表示某種特殊或異常情況時。許多開發者習慣性地使用None來表示這些特殊情況&#xff0c;但這種方法往往會導致意想不到的錯…

從反射到方法句柄:深入探索Java動態編程的終極解決方案

&#x1f31f; 你好&#xff0c;我是 勵志成為糕手 &#xff01; &#x1f30c; 在代碼的宇宙中&#xff0c;我是那個追逐優雅與性能的星際旅人。 ? 每一行代碼都是我種下的星光&#xff0c;在邏輯的土壤里生長成璀璨的銀河&#xff1b; &#x1f6e0;? 每一個算法都是我繪制…

算法_python_學習記錄_01

人心的成見是一座大山。一旦有山擋在面前&#xff0c;則很難到達下一站。所需要做的&#xff0c;是穿過這座山。 偶然間看了一個視頻&#xff0c;說的是EMASMA的自動交易策略&#xff0c;這個視頻做的很用心&#xff0c;在入場的時間不僅要看EMA的金叉&#xff0c;還需要看其他…

機器翻譯中的語言學基礎詳解(包括包括語法、句法和語義學等)

文章目錄一、語法&#xff08;Grammar&#xff09;&#xff1a;語言規則的底層框架1.1 傳統語法理論的應用1.2 生成語法&#xff08;Generative Grammar&#xff09;1.3 依存語法&#xff08;Dependency Grammar&#xff09;二、句法&#xff08;Syntax&#xff09;&#xff1a…

MQTT:Dashboard訪問授權

目錄一、認證1.1 創建認證器1.2 多認證器二、授權2.1 ACL文件授權配置2.2 使用內置數據庫授權配置一、認證 認證&#xff1a;就是驗證客戶端的身份。 1.1 創建認證器 選擇認證方式配置數據源配置數據源的相關參數 認證器創建之后&#xff0c;在使用客戶端連接Dashboard時&am…

Serper注冊無反應

google郵箱才行&#xff0c;163郵箱注冊無反應&#xff0c;其他郵箱沒試過 在嘗試websailor系列的時候&#xff0c;需要注冊serper&#xff0c;獲取Google Search Key serper.dev/dashboard

聊聊經常用的微服務

聊聊微服務 架構演變 單體架構&#xff1a; All in One&#xff0c;所有的功能模塊都在一個工程里。 SOA架構&#xff1a; 這個架構當不當正不正&#xff0c;對于現在來說&#xff0c;有點老&#xff0c;甚至需要ESB&#xff0c;WebService之類的&#xff0c;基本不會使用了。…

第十四屆藍橋杯青少年組省賽 編程題真題題解

明天我就要考藍橋杯省賽了&#xff0c;本蒟蒻已瑟瑟發抖&#xff0c;所以現在寫一篇文章。 題目分別為&#xff1a; 1.??????B4270 [藍橋杯青少年組省賽 2023] 特殊運算符 2.B4271 [藍橋杯青少年組省賽 2023] 四葉玫瑰數 3.B4272 [藍橋杯青少年組省賽 2023] 質因數的…

HTML全景效果實現

我將為您創建一個精美的360度全景效果頁面&#xff0c;使用Three.js庫實現沉浸式全景體驗&#xff0c;并提供用戶友好的控制界面&#xff0c;完整代碼看文章末尾。 設計思路 使用Three.js創建全景球體 添加控制面板用于切換不同場景 實現自動旋轉和手動控制選項 添加加載狀…

Python 屬性描述符(描述符用法建議)

描述符用法建議 下面根據剛剛論述的描述符特征給出一些實用的結論。 使用特性以保持簡單 內置的 property 類創建的其實是覆蓋型描述符&#xff0c;__set__ 方法和 __get__ 方法都實現了&#xff0c;即便不定義設值方法也是如此。特性的 __set__ 方法默認拋出 AttributeError: …

Milvus 向量數據庫內存使用相關了解

1、支持 MMap 的數據存儲在 Milvus 中&#xff0c;內存映射文件允許將文件內容直接映射到內存中。這一功能提高了內存效率&#xff0c;尤其是在可用內存稀缺但完全加載數據不可行的情況下。這種優化機制可以增加數據容量&#xff0c;同時在一定限度內確保性能&#xff1b;但當數…

C++編程之旅-- -- --默認成員函數(全詳解)

目錄前言構造函數構造函數形式&#xff1a;構造函數的特性&#xff1a;explicit關鍵字析構函數析構函數的概念析構函數的特性含有類類型的成員變量的類析構函數的調用拷貝構造函數拷貝構造函數的概念拷貝構造函數的特性淺拷貝和深拷貝&#xff1a;拷貝構造函數典型調用場景&…

Linux網絡編程:TCP的遠程多線程命令執行

目錄 前言&#xff1a; 一、前文補充 二、服務端的修改 三、Command類的新增 前言&#xff1a; 好久不見&#xff0c;最近忙于其他事情&#xff0c;就耽誤了咱們的Linux的網絡部分的學習。 今天咱們先來給之前所學的TCP的部分進行一個首尾工作&#xff0c;主要是給大家介紹…

重學React(三):狀態管理

背景&#xff1a; 繼續跟著官網的流程往后學&#xff0c;之前已經整理了描述UI以及添加交互兩個模塊&#xff0c;總體來說還是收獲不小的&#xff0c;至少我一個表面上用了四五年React的前端小卡拉米對React的使用都有了新的認知。接下來就到了狀態管理&#xff08;React特地加…

java web項目入門了解

目錄一、項目流程1. 使用servle2. 使用框架二、了解java web項目構造1. 項目目錄結構2. 查看頁面訪問順序3. 發起請求&#xff1a;jqueryajax4. 接受參數5. JSONJSON 數組三、get和post請求區別一、項目流程 1. 使用servle 有客戶端和服務端&#xff0c;客戶端和服務端進行交…

網絡資源模板--基于Android Studio 實現的日記本App

目錄 一、測試環境說明 二、項目簡介 三、項目演示 四、部設計詳情&#xff08;部分) 創建修改頁面 五、項目源碼 一、測試環境說明 電腦環境 Windows 11 編寫語言 JAVA 開發軟件 Android Studio (2020) 開發軟件只要大于等于測試版本即可(近幾年官網直接下載也可…

GO的啟動流程(GMP模型/內存)

目錄第一部分&#xff1a;程序編譯第二部分&#xff1a;函數解讀1&#xff09;Golang 核心初始化過程2&#xff09;創建第一個協程3&#xff09;啟動系統調度4&#xff09;跳轉main函數5&#xff09;總結第三部分&#xff1a;GMP模型Goroutine流程解讀第四部分&#xff1a;內存…

OLTP與OLAP:實時處理與深度分析的較量

OLTP&#xff08;Online Transaction Processing&#xff09;定義&#xff1a;OLTP 系統主要用于管理事務性應用程序的數據。這類系統需要支持大量的短時、快速的交互式事務&#xff0c;比如銀行交易、在線購物訂單等。特點&#xff1a;實時處理&#xff1a;OLTP 系統要求對數據…

數據安全與隱私保護:企業級防護策略與技術實現

引言&#xff1a;數據安全的新時代挑戰在數字化轉型加速的今天&#xff0c;數據已成為企業最核心的資產。然而&#xff0c;數據泄露事件頻發&#xff0c;據 IBM《2024 年數據泄露成本報告》顯示&#xff0c;全球數據泄露平均成本已達445 萬美元&#xff0c;較 2020 年增長了 15…

AI_RAG

一.為什么需要RAG&#xff08;AI幻覺&#xff09;大模型LLM在某些情況下給出的回答很可能錯誤的&#xff0c;涉及虛構甚至是故意欺騙的信息。二.什么是RAGRAG是一種結合“信息檢索”和“文本生成”的技術&#xff0c;旨在提升生成式AI模型的準確性和可靠性。它通過以下兩個核心…