【C++高階三】AVL樹深度剖析

【C++高階三】AVL樹深度剖析

  • 1.什么是AVL樹
  • 2.AVL樹的實現
    • 2.1節點類和基本結構
    • 2.2插入
    • 2.3旋轉處理
      • 2.3.1左單旋
      • 2.3.2右單旋
      • 2.3.3左右雙旋
      • 2.3.4右左雙旋

1.什么是AVL樹

AVL樹也叫二叉搜索平衡樹
因為二叉搜索樹如果插入順序是有序的,那么這棵樹的查找效率將會是O(N),所以說在實際情況下,二叉搜索很少被使用
為了解決這個缺點,誕生了AVL樹

左右子樹都是AVL樹,左右子樹高度差絕對值(平衡因子值)不超過1(平衡因子值不一定是1,這只是一種實現方案)

一顆高度不平衡的樹:
在這里插入圖片描述
一顆AVL樹:
在這里插入圖片描述

一般的二叉搜索樹在插入新節點以及刪除節點時,都有可能會破壞樹的平衡,所以AVL樹需要對插入以及刪除接口做修改,每次插入刪除時,都要檢測一下當前的樹時候符合AVL樹,如果不符合,要做出相應的調整措施
由于AVL樹的這種特殊性質,使得它的查找效率是百分百的O(logn)

2.AVL樹的實現

2.1節點類和基本結構

template<class K, class V>
struct AVLTreeNode //AVL樹節點
{AVLTreeNode(const pair<K, V>& kv): _left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _bf(0){}//用三叉鏈,方便更新祖先的平衡因子AVLTreeNode<K,V>* _left;AVLTreeNode<K,V>* _right;AVLTreeNode<K,V>* _parent;pair<K, V> _kv;//存儲的數據int _bf;//balance factor平衡因子
};

_left:指向左子樹
_right:指向右子樹
_parent:指向父節點
_bf:平衡因子
_kv:存儲的鍵值對

template<class K,class V>
struct AVLTree //AVL樹
{typedef AVLTreeNode<K, V> Node;
private:Node* _root;//定義一個根節點
};

2.2插入

插入有三個步驟:

  1. 按照二叉搜索樹規則插入節點
  2. 插入完成后更新平衡因子
  3. 若平衡因子不正確需要采取措施

更新平衡因子規則:

  1. 新增在右,父親的平衡因子_bf加一
    新增在左,父親的平衡因子_bf減一
  2. 更新完成后,父親的_bf == 1 || -1,說明父親插入前的_bf一定是0,插入后左右子樹一邊高一邊低,需要繼續向上更新平衡因子

在這里插入圖片描述

  1. 更新完成后父親的bf==0,說明父親在插入前的_bf是1/-1,并且插入后兩邊高度一致,不需要繼續往上更新
    在這里插入圖片描述

  2. 更新完成后父親的_bf == 2 || -2,打破了平衡,父親所在的子樹要旋轉處理
    在這里插入圖片描述

bool insert(const pair<K,V>& kv)//按照二叉搜索樹的方式插入值
{if(_root == nullptr){_root = new Node(kv);return true; }Node* cur = _root;//要插入節點的位置Node* parent = nullptr;//其父親的位置while(cur)//找到插入的位置{if(kv.first > cur->_kv.first){parent = cur;cur = cur->_right;}else if(kv.first < cur->_kv.first){parent = cur;cur = cur->_left;}else{return false;}}//找到了位置cur,開辟空間cur = new Node(kv);//父親指向子if(kv.first > parent->_kv.first){	parent->_right = cur;}else{parent->_left = cur;}//子指向父cur->_parent = parent;//插入完成,檢查平衡因子//沿插入位置cur向上更新平衡因子while(parent)//parent需要不斷向上更新{	if(cur == parent->right){parent->_bf++;}else{parent->_bf--;}//不用向上更新if(parent->_bf == 0){	break;}//高度出現變化,向上更新平衡因子else if(parent->_bf == 1 || parent->_bf == -1){	parent = parent->parent;cur = cur->parent;}else if(parent->_bf == 2){//parent所在的子樹不平衡了,需要旋轉處理//后面會處理這處}}
}

2.3旋轉處理

2.3.1左單旋

在這里插入圖片描述

2.3.2右單旋

在這里插入圖片描述

2.3.3左右雙旋

在這里插入圖片描述

2.3.4右左雙旋

在這里插入圖片描述

void RotateL(Node* parent)
{Node* subR = parent->_right;Node* subRL = subR->_+left;parent->_right = subRL;if(subRL){subRL->_parent = parent;}Node* parentparent = parent->_parent;subR->_left = parent;parent->_parent = subR;if(parent == _root){_root = subR;subR->_parent = nullptr;}else{if(parentparent->_left = parent){parentparent->_left = subR;}else{parentparent->_right = subR;}subR->_parent = parentparent;}subR->_bf = parent->_bf = 0;
}
void RotateR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;Node* ppNode = parent->_parent;subL->_right = parent;parent->_parent = subL;if (_root == parent){_root = subL;subL->_parent = nullptr;}else{if (ppNode->_left == parent)ppNode->_left = subL;elseppNode->_right = subL;subL->_parent = ppNode;}subL->_bf = parent->_bf = 0;
}
void RotateLR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;RotateL(parent->_left);RotateR(parent);subLR->_bf = 0;if (bf == 1){parent->_bf = 0;subL->_bf = -1;}else if (bf == -1){parent->_bf = 1;subL->_bf = 0;}else if (bf == 0){parent->_bf = 0;subL->_bf = 0;}else assert(false);
}
void RotateRL(Node* parent)
{Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(parent->_right);RotateL(parent);subRL->_bf = 0;if (bf == 1){subR->_bf = 0;parent->_bf = -1;}else if (bf == -1){subR->_bf = 1;parent->_bf = 0;}else if (bf == 0){parent->_bf = 0;subR->_bf = 0;}else assert(false);
}

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

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

相關文章

LangChain 文本分割器深度解析:從原理到落地應用(上)

食用指南 LangChain 作為大語言模型應用開發框架&#xff0c;文本分割器是其核心組件之一&#xff0c;本文以此作為切入點&#xff0c;詳細介紹文本分割的作用、策略、以及常見的文本切割器應用。考慮到篇幅過長&#xff0c;故拆分為上、中、下三篇&#xff0c;后續會在中篇介…

【Java高頻面試問題】高并發篇

【Java高頻面試問題】高并發篇 Kafka原理核心組件高吞吐核心機制高可用設計 Kafka 如何保證消息不丟失如何解決Kafka重復消費一、生產者端&#xff1a;根源防重二、消費者端&#xff1a;精準控制三、業務層&#xff1a;冪等性設計&#xff08;核心方案&#xff09; 如何解決Kaf…

關于結構體,排序,遞推的詳細講解(從屬于GESP四級)

本章內容 排序算法基礎 結構體 遞推 簡單雙指針 一、排序算法基礎三劍客 冒泡 Bubble、選擇 Selection、插入 Insertion 1. 預備知識 1.1 排序算法評價指標 指標 含義 影響答題的典型問法 時間復雜度 算法在最壞、平均或最好情況下所需比較 / 交換次數 “寫出此算法…

離線部署docker中的containerd服務

containerd 是一個行業標準的容器運行時&#xff0c;專注于簡單、健壯的容器執行。它是從 Docker 中分離出來的項目&#xff0c;旨在作為一個底層的運行時接口&#xff0c;供更高層次的容器管理層使用。 containerd 負責鏡像傳輸、存儲、容器執行、網絡配置等工作。它向上為 Do…

web布局15

CSS 網格布局除了提供定義網格和放置網格項目的相關屬性之外&#xff0c;也提供了一些控制對齊方式的屬性。這些控制對齊方式的屬性&#xff0c;和 Flexbox 布局中的對齊屬性 justify-* 、align-* 、*-items 、*-content 、 *-self 等是相似的&#xff1a; 在網格布局中可以用它…

leetcode 291. Word Pattern II和290. Word Pattern

目錄 291. Word Pattern II 290. Word Pattern 291. Word Pattern II 回溯法哈希表 class Solution {unordered_map<char,string> hashmap;unordered_set<string> wordset; public:bool wordPatternMatch(string pattern, string s) {return backtrack(pattern,…

大模型的開發應用(十三):基于RAG的法律助手項目(上):總體流程簡易實現

RAG法律助手項目&#xff08;上&#xff09;&#xff1a;總體流程簡易實現 1 項目介紹1.1 方案選型1.2 知識文檔 2 文檔解析3 知識庫構建3.1 構建知識節點3.2 嵌入向量初始化3.2 向量存儲 4 查詢4.1 初始化大模型4.2 模型響應4.2 本文程序存在的問題 完整代碼 1 項目介紹 本項…

覆蓋遷移工具選型、增量同步策略與數據一致性校驗

1 引言 在當今數據驅動的時代&#xff0c;數據遷移已成為系統迭代、數據庫升級、云遷移和架構演進中的關鍵環節。根據Gartner的調研&#xff0c;超過70%的企業級數據遷移項目因工具選擇不當或同步策略缺陷而延期或失敗。數據遷移不僅僅是簡單的數據搬運&#xff0c;而是涉及數…

`docker run -it --rm` 筆記250624

docker run -it --rm 筆記250624 docker run -it --rm 是一個強大且常用的 Docker 命令組合&#xff0c;特別適合交互式開發和調試場景。以下是詳細解析和使用指南&#xff1a; 參數解析 參數作用典型場景-i保持 STDIN 打開&#xff08;交互模式&#xff09;需要輸入命令的交…

解鎖阿里云AnalyticDB:數據倉庫的革新利器

AnalyticDB&#xff1a;云數據倉庫新勢力 在數字化浪潮中&#xff0c;數據已成為企業的核心資產&#xff0c;而云數據倉庫作為數據管理與分析的關鍵基礎設施&#xff0c;正扮演著愈發重要的角色。阿里云 AnalyticDB 作為云數據倉庫領域的佼佼者&#xff0c;以其卓越的性能、創…

【PX30 Qt 5.15 交叉編譯環境搭建完整指南】

PX30 Qt 5.15 交叉編譯環境搭建完整指南 (Ubuntu 20.04 → PX30 aarch64) &#x1f3af; 項目概覽 本指南詳細記錄了在Ubuntu 20.04上搭建針對Rockchip PX30的Qt 5.15.2交叉編譯環境的完整過程&#xff0c;包括實際操作步驟、遇到的問題及解決方案。 目標平臺: Rockchip PX3…

深入理解讀寫鎖 ReadWriteLock

在高性能并發編程中&#xff0c;如何有效地管理共享資源的訪問是核心挑戰之一。傳統的排他鎖&#xff08;如ReentrantLock&#xff09;在讀多寫少的場景下&#xff0c;性能瓶頸尤為突出&#xff0c;因為它不允許并發讀取。Java并發包&#xff08;java.util.concurrent.locks&am…

Unity Addressable使用之檢測更新流程

補充知識 關鍵文件說明 Addressable打包后會生成多種文件&#xff0c;主要包括 .hash、.json 和 .bundle 文件&#xff0c;它們各自有不同的作用。 .hash 文件&#xff08;哈希文件&#xff09; 作用&#xff1a; 用于 版本對比&#xff0c;檢查資源是否有更新。存儲的是 資…

Elasticsearch 中實現推薦搜索(方案設想)

1. 存儲商品數據的數據類型 為了支持推薦搜索&#xff0c;商品數據通常需要包含以下字段&#xff1a; 商品索引結構 PUT /products {"mappings": {"properties": {"product_id": {"type": "keyword" // 商品 ID},"…

Aerotech系列(4)Aerotech.A3200名空間

IconTypeDescriptionAxisMask Represents a selection of axes Controller Represents a controller Allows configuring and c

React Router 是怎么實現靈活導航的?

&#x1f399; 歡迎來到《前端達人 React播客書單》第 21 期。 視頻版&#xff08;播客風格更精彩&#xff09; 今天我們不講 Hook&#xff0c;來拆解前端開發中另一個高頻組件&#xff1a;React Router 的進階導航模式。 你可能用過 <Link> 或 <Route>&#xff0…

Modbus TCP轉Profibus DP網關與JF - 600MT 稱重變送器輕松實現數據互換

Modbus TCP轉Profibus DP網關與JF - 600MT 稱重變送器輕松實現數據互換 在工業自動化領域&#xff0c;不同設備之間的通信與數據交互至關重要。Modbus TCP轉Profibus DP網關作為連接不同協議設備的關鍵橋梁&#xff0c;發揮著不可或缺的作用。本文將以JF - 600MT稱重變送器與3…

聊聊 SQL 注入那些事兒

相信大家對于學校們糟糕的網絡環境和運維手段都早有體會&#xff0c;在此就不多做吐槽了。今天我們來聊一聊SQL注入相關的內容。 何謂SQL注入&#xff1f; SQL注入是一種非常常見的數據庫攻擊手段&#xff0c;SQL注入漏洞也是網絡世界中最普遍的漏洞之一。大家也許都聽過某某學…

多傳感器融合

目錄 多傳感器融合 多傳感器融合的方向 傳感器融合方案介紹 LOAM LIO-SAM LVI-SAM 多線激光雷達性質 什么是運動畸變 兩步優化的幀間里程記 IMU 器件介紹及選型建議 IMU 標定方法簡介 視覺里程計 VS 激光里程計 LVI-SAM 激光視覺融合思路簡介 多傳感器融合工程實踐經驗與技巧 多…

Auto-GPT vs ReAct:兩種智能體思路對決

目錄 Auto-GPT vs ReAct&#xff1a;兩種智能體思路對決 &#x1f9e0; 一、智能體的演化背景 &#x1f9e9; 二、Auto-GPT&#xff1a;自循環的執行體 &#x1f50d; 三、ReAct&#xff1a;推理 行動的交錯協同 ?? 四、對比總結 &#x1f6e0; 五、你該選誰&#xff…