【數據結構】紅黑樹原理及實現

目錄

  • 一. 紅黑樹的概念
    • 1. 紅黑樹的規則
      • 思考
    • 2. 紅黑樹的效率
  • 二.紅黑樹的實現
    • 1. 紅黑樹的結構
    • 2. 紅黑樹的插入
    • 3. 紅黑樹的平衡調整
      • 情況1:變色
      • 情況2:單旋+變色
      • 情況3:雙旋+變色
    • 4. 紅黑樹插入及平衡調整代碼實現
    • 5.紅黑樹的驗證

一. 紅黑樹的概念

二叉樹的優化,每個節點有一個變量表示結點的顏色,可以是紅色或黑色,通過對節點顏色的約束,可以確保沒有路徑比其他路徑長出兩倍,接近平衡。

1. 紅黑樹的規則

  1. 每個節點不是紅色就是黑色
  2. 根節點是黑色
  3. 不能有相連的紅色節點,也就是說一個節點如果是紅色,他的孩子一定是黑色
  4. 對于任意一條從根節點到空的路徑,黑色節點的數量都相同
    在這里插入圖片描述

思考

為什么紅黑樹的最長路徑不超過最短路徑的兩倍?
每條路徑都有相同數量的黑色節點,假設一條路上全是黑色,這是最短的路徑長度為h,由于不能有相連的紅色節點,最長的路徑是一個紅一個黑的路徑排列,長度為2h,所以對任意一條路徑長度x來說,h<=x<=2h

2. 紅黑樹的效率

假設節點數量為N,h為最短路徑長度,2h-1 <= N < 22*h-1, 分析可得h=logN,由此可見最快的查找為logN,最壞的情況下高度為2h,查找效率也還是2*logN,所以紅黑樹的查找效率為O(logN)

二.紅黑樹的實現

1. 紅黑樹的結構

用bool類型來定義樹的顏色,
定義parent,left和right指針方便后續的調整

typedef bool RBTreeColor;
const  RBTreeColor RBTreeRed = true;
const  RBTreeColor RBTreeBlack = false;template <class K,class V>
struct RBTreeNode
{typedef RBTreeNode Node;pair<K, V> _kv;Node* _parent;Node* _left;Node* _right;RBTreeColor _color;RBTreeNode(const pair<K,V>& kv):_kv(kv),_parent(nullptr),_left(nullptr),_right(nullptr),_color(RBTreeRed){}
};
template <class K, class V>
class RBTree
{
public:typedef RBTreeNode Node;private:Node*  _root=nullptr;
};

2. 紅黑樹的插入

  1. 先按照二叉樹的規則進行插入
  2. 如果是空樹插入,則新插入的節點為黑色,成為樹的根,否則新插入的節點為紅色,這是為了維護每條路徑上的黑色節點數量相同這個規則
  3. 非空樹插入后,新增節點為紅色,如果父節點為黑色,不違反插入規則,插入結束
  4. 非空樹插入后,新增節點為紅色,如果父節點也為紅色,違反插入規則,需要進行平衡調整

3. 紅黑樹的平衡調整

走到了平衡這一步,一定是因為出現了相連的兩個紅色節點,新插入節點c(cur)為紅色,插入節點的父節點p(parent)一定也為紅色,父節點的父節點g(grandparent)一定是黑色,這三個節點的顏色都是固定的,關鍵看父節點兄弟節點u(uncle)的情況,根據u的情況,可以分出幾種平衡調整規則

情況1:變色

u存在且為紅,p和u變成黑色,g變成紅色,把g當成新的c,繼續向上更新
分析:以g為根的左右子樹的黑色節點數是一定的,把g變成紅色,p和u變成黑色,不會影響左右子樹的黑色節點數,以g為根的樹的黑色節點數的也沒有改變,由于g的父節點也是紅色,所以需要把g當成新的c節點繼續向上更新
在這里插入圖片描述

情況2:單旋+變色

u不存在或者存在且為黑
u不存在時,c一定是新增節點;u存在且為黑時,c一定不是新增節點,符合情況一
分析:這種情況必須使p的變成黑色,g變成紅色,然后旋轉,讓p變成這棵樹新的根,由于新的根是黑色,不管他的父節點是什么,都符合紅黑樹的規則,插入結束
關于旋轉的具體分析參照AVL數章節
在這里插入圖片描述
當p是g的左孩子,c是p的左孩子,以g為旋轉點,進行右單旋,p變成新的根,

在這里插入圖片描述
當p是g的右孩子,c是p的右孩子,以g為旋轉點,進行左單旋,p變成新的根,
在這里插入圖片描述
在這里插入圖片描述

情況3:雙旋+變色

u不存在或者存在且為黑
u不存在時,c一定是新增節點;u存在且為黑時,c一定不是新增節點,符合情況一
分析:和情況二類似,根據情況單旋變雙旋
在這里插入圖片描述
當p是g的左孩子,c是p的右孩子,先以p為旋轉點,進行左單旋,然后以g為旋轉點,進行右單旋,c變黑,g變紅,c變成這棵樹新的根

在這里插入圖片描述當p是g的右孩子,c是p的左孩子,先以p為旋轉點,進行右單旋,然后以g為旋轉點,進行左單旋,c變黑,g變紅,c變成這棵樹新的根
在這里插入圖片描述
在這里插入圖片描述

4. 紅黑樹插入及平衡調整代碼實現

旋轉代碼參考AVL章節—>AVL原理及實現

};
template <class K, class V>
bool RBTree < K,V>::Insert(const pair<K, V>& kv)
{if (_root == nullptr){_root = new Node(kv);_root->_color = RBTreeBlack;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);//判斷新增節點使父節點左還是右if (parent->_kv.first < kv.first)parent->_right = cur;elseparent->_left = cur;cur->_parent = parent;while (parent && parent->_color == RBTreeRed){Node* grandfather = parent->_parent;//  g//p   u//p為g的左代碼實現if (parent == grandfather->_left){Node* uncle = grandfather->_right;//  u存在且為紅,p和u變黑,g變紅,改變cur和p的指向,繼續向上變;if (uncle && uncle->_color == RBTreeRed){parent->_color = uncle->_color = RBTreeBlack;grandfather->_color = RBTreeRed;cur = grandfather;parent = grandfather->_parent;}// u不存在或存在且為黑else{//      g//    p    u//  c//單旋加變色,c為p的左,   p變成新的根,p變黑,g變紅if (cur == parent->_left){RorateR(grandfather);parent->_color = RBTreeBlack;grandfather->_color = RBTreeRed;}//        g//    p         u//       c//雙旋加變色,c為p的右,else{RorateLR(grandfather);cur->_color = RBTreeBlack;grandfather->_color = RBTreeRed;}}}else{ //這里是p為g的情}return true;}

5.紅黑樹的驗證

這里需要回憶一下紅黑樹四條規則,只要滿足了這四條規則,就符合紅黑樹的標準
在這里插入圖片描述

  1. 節點顏色用bool值標記,天然滿足這個規則
  2. 檢查根節點是否是黑色即可
  3. 一個節點可能不止一個孩子,但一個節點只能有一個父親,所以遇到一個紅色節點就查他的父親是否是黑色,滿足這點就滿足了第三點
  4. 可以先序計算任意一條路徑黑色節點的數量 ,然后讓每個路徑的黑色節點數和他比較,如果全都相等就滿足第四條規則
template <class K, class V>
bool RBTree < K, V>::check(Node* root, int count, const int blackNum)
{// 檢查到空樹就比較黑色節點數if (root == nullptr){if (count == blackNum)return true;elsereturn false;}//如果有連續的紅色節點,返回false,// 這里的root不會是根節點,如果是根節點在IsBanlance函數就已經檢測出并返回了,所以每一個紅色節點的父節點都不會為空if (root->_color == RBTreeRed && root->_parent->_color == RBTreeRed)return false;//遇到黑色節點if (root->_color == RBTreeBlack)count++;return check(root->_left, count, blackNum) && check(root->_right, count, blackNum);
}
template <class K, class V>
bool RBTree < K, V>::IsBanlance(Node* root)
{if (root == nullptr)return true;if (root->_color == RBTreeRed)return false;Node* cur = root;int count = 0;while (cur){if (cur->_color == RBTreeBlack)count++;cur = cur->_left;}
}

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

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

相關文章

時間復雜度分析

復雜度分析的必要性&#xff1a; 當給我們一段代碼時&#xff0c;我們是以什么準則來判斷代碼效率的高低呢&#xff1f;每一段代碼都會消耗一段時間&#xff0c;或占據一段數據空間&#xff0c;那么自然是在實現相同功能的情況下&#xff0c;代碼所耗時間最少&#xff0c;所占…

L1-1、Prompt 是什么?為什么它能“控制 AI”?

*Prompt 入門 L1-1 想象一下&#xff0c;你只需輸入一句話&#xff0c;AI 就能自動為你寫一篇文案、生成一份報告、甚至規劃你的創業計劃。這種“對話即編程”的背后魔法&#xff0c;就是 Prompt 的力量。 &#x1f50d; 一、Prompt 的定義與由來 Prompt&#xff08;提示詞&am…

微信小程序文章管理系統開發實現

概述 在內容為王的互聯網時代&#xff0c;高效的文章管理系統成為各類平臺的剛需。幽絡源平臺今日分享一款基于SSM框架開發的微信小程序文章管理系統完整解決方案&#xff0c;該系統實現了多角色內容管理、智能分類、互動交流等功能。 主要內容 一、用戶端功能模塊 ??多角…

【Python-Day 5】Python 格式化輸出實戰:%、format()、f-string 對比與最佳實踐

Langchain系列文章目錄 01-玩轉LangChain&#xff1a;從模型調用到Prompt模板與輸出解析的完整指南 02-玩轉 LangChain Memory 模塊&#xff1a;四種記憶類型詳解及應用場景全覆蓋 03-全面掌握 LangChain&#xff1a;從核心鏈條構建到動態任務分配的實戰指南 04-玩轉 LangChai…

R7周:糖尿病預測模型優化探索

&#x1f368; 本文為&#x1f517;365天深度學習訓練營中的學習記錄博客 &#x1f356; 原作者&#xff1a;K同學啊 一、數據預處理 1.設置GPU import torch.nn.functional as F import torch.nn as nn import torch, torchvisiondevice torch.device("cuda"…

使用Tortoise-ORM和FastAPI構建評論系統

title: 使用Tortoise-ORM和FastAPI構建評論系統 date: 2025/04/25 21:37:36 updated: 2025/04/25 21:37:36 author: cmdragon excerpt: 在models.py中定義了Comment模型,包含id、content、created_at、updated_at字段,并與User和Article模型建立外鍵關系。schemas.py中定義了…

【VS Code】如何使用SSH打開遠程服務器Docker上的項目或文件夾

要在VS Code中使用SSH打開遠程服務器Docker上的項目或文件夾&#xff0c;您需要結合使用VS Code的Remote - SSH擴展和Docker的遠程訪問功能。以下是詳細步驟&#xff1a; 安裝VS Code Remote - SSH擴展 打開VS Code。點擊左側活動欄的擴展圖標&#xff08;或使用快捷鍵CtrlShif…

NHANES指標推薦:PLP

文章題目&#xff1a;Association of pyridoxal 5-phosphate (PLP) with lipid profiles: a population-based cohort study DOI&#xff1a;10.3389/fnut.2025.1545301 中文標題&#xff1a;5-磷酸吡哆醛 (PLP) 與血脂譜的關系&#xff1a;一項基于人群的隊列研究 發表雜志&am…

MySQL 詳解之備份與恢復策略:數據安全的最后一道防線

在任何信息系統中,數據都是最寶貴的資產。數據的丟失可能源于多種原因:硬件故障、人為誤操作、軟件 Bug、惡意攻擊,甚至自然災害。一旦發生數據丟失,如果沒有有效的備份和恢復機制,后果可能是災難性的,可能導致業務中斷、經濟損失甚至法律責任。 數據庫備份與恢復,正是…

2026《數據結構》考研復習筆記五(棧、隊列)

棧、隊列 一、棧1.卡特蘭數2.不合法的出棧序列 二、隊列1.循環隊列2.輸入輸出受限隊列&#xff08;四個數1234&#xff09; 三、算法1.棧在括號匹配中的應用2.中綴表達式求值&#xff08;通過轉化為后綴表達式再后綴表達式求值&#xff09;3.中綴表達式轉化為后綴表達式4.后綴表…

深入解析微軟MarkitDown:原理、應用與二次開發指南

一、項目背景與技術定位 微軟開源的MarkitDown并非簡單的又一個Markdown解析器&#xff0c;而是針對現代文檔處理需求設計的工具鏈核心組件。該項目誕生于微軟內部大規模文檔系統的開發實踐&#xff0c;旨在解決以下技術痛點&#xff1a; 大規模文檔處理性能&#xff1a;能夠高…

pyinstaller打包paddleocr發生錯誤解決

python環境是3.9&#xff0c;github paddleocr v2.10.0。 一個非常簡單的案例如下&#xff0c;打包時發生錯誤。 import requests from paddleocr import PaddleOCR if __name__ "__main__":paddleocr_ocr PaddleOCR(use_angle_clsTrue, langch,det_model_dirmode…

算法之回溯法

回溯法 回溯法定義與概念核心思想回溯法的一般框架偽代碼表示C語言實現框架 回溯法的優化技巧剪枝策略實現剪枝的C語言示例記憶化搜索 案例分析N皇后問題子集和問題全排列問題尋路問題 回溯法的可視化理解決策樹狀態空間樹回溯過程 回溯法與其他算法的比較回溯法與動態規劃的區…

命令行指引的嘗試

效果 步驟 首先初始化一個空的項目&#xff0c;然后安裝一些依賴 npm init -y npm install inquirer execa chalk ora至于這些依賴是干嘛的&#xff0c;如下圖所示&#xff1a; 然后再 package.json 中補充一個 bin 然后再根目錄下新建一個 index.js , 其中的內容如下 #!/…

探秘LLM推理模型:hidden states中藏著的self verification的“鑰匙”

推理模型在數學和邏輯推理等任務中表現出色&#xff0c;但常出現過度推理的情況。本文研究發現&#xff0c;推理模型的隱藏狀態編碼了答案正確性信息&#xff0c;利用這一信息可提升推理效率。想知道具體如何實現嗎&#xff1f;快來一起來了解吧&#xff01; 論文標題 Reasoni…

流量抓取工具(wireshark)

協議 TCP/IP協議簇 網絡接口層&#xff08;沒有特定的協議&#xff09;PPPOE 物理層數據鏈路層 網絡層: IP(v4/v6) ARP&#xff08;地址解析協議) RARP ICMP(Internet控制報文協議) IGMP傳輸層&#xff1a;TCP(傳輸控制協議&#xff09;UDP&#xff08;用戶數據報協議)應用層…

.NET倉儲層在 using 塊中創建 SqlSugarClient 的風險

如題&#xff0c;先看代碼示例 using 塊的使用 public ISugarQueryable<T> GetSet(Expression<Func<T, bool>> whereExpression null) {using (SqlSugarClient dbClient SqlSugarInstance.GetInstance()){var query dbClient.Queryable<T>();if (w…

C語言----函數棧幀講解

目錄 1.函數棧幀是什么? 2. 理解函數棧幀能解決什么問題 3、函數棧幀的創建和銷毀具體過程 3.1 什么是棧 3.2 認識相關寄存器和匯編指令 3.3函數棧幀的創建和銷毀 3.3.1 預備知識 3.3.2 函數的調用堆棧 3.3.3 準備環境 3.3.4 轉到反匯編 3.3.5 函數棧幀的創建 3.3…

代碼隨想錄學習筆記---二叉樹

學習目標&#xff1a; 學習代碼隨想錄–二叉樹 每天學習1道,復習兩道 學習內容&#xff1a; 2025.4.7 復習內容: 24. 兩兩交換鏈表中的節點 25. 最大二叉樹 學習內容 26. 合并二叉樹 2025.4.8 復習內容: 27. 二分查找 28. 合并二叉樹 29. 27. 移除元素 學習內容: 30. 二叉…

Git ——提交至github,Vercel拉取,更新不了項目的問題解決

首先因為github上有個錯誤 1 failing check Vercel - No GitHub account was found matching the commit author email address 發現好像是vercel拉取不了項目&#xff0c;vercel登錄的郵箱與我此次提交更改的郵箱不匹配&#xff0c;查看Git的user確實如此&#xff08;之前的…