C++的數據結構(十):AVL樹

????????AVL樹是一種自平衡的二叉搜索樹,得名于其發明者G.M. Adelson-Velsky和E.M. Landis。在AVL樹中,任何節點的兩個子樹的高度最多相差1,這種性質確保了AVL樹的查找、插入和刪除操作的時間復雜度接近O(log n)。

????????AVL樹是一種二叉搜索樹,它通過調整節點間的結構來保持樹的平衡。平衡因子(Balance Factor)是AVL樹中一個關鍵的概念,定義為節點的左子樹高度與右子樹高度的差。在AVL樹中,任何節點的平衡因子的絕對值不得超過1。如下圖所示。

?????????AVL樹通過旋轉操作來保持樹的平衡,AVL樹在節點插入或刪除后,若導致樹不平衡,則會通過四種旋轉操作之一來重新平衡樹。這四種旋轉操作分別是:左旋、右旋、左右旋和右左旋。

????????1.?左旋操作通常發生在右子樹比左子樹高太多的時候。具體操作是:將當前節點(我們稱其為T)的右子節點(我們稱其為R)提升為新的根節點,將T節點降為R的左子節點,R的左子節點則成為T的右子節點。示例代碼如下。

struct TreeNode {int val;int height;TreeNode* left;TreeNode* right;TreeNode(int val) : val(val), height(1), left(nullptr), right(nullptr) {}
};TreeNode* leftRotate(TreeNode* x) {TreeNode* y = x->right;  // y是x的右子節點x->right = y->left;      // y的左子節點成為x的右子節點y->left = x;            // x成為y的左子節點// 更新高度x->height = 1 + max(height(x->left), height(x->right));y->height = 1 + max(height(y->left), height(y->right));return y;  // 新的根節點
}

? ? ? ? 2. 右旋操作與左旋相反,發生在節點不平衡,且平衡因子小于-1,同時左子節點的平衡因子小于等于0時。我們將左子節點提升為當前節點的父節點,當前節點變為左子節點的右子節點,完成右旋。示例代碼如下。

TreeNode* rightRotate(TreeNode* y) {TreeNode* x = y->left;  // x是y的左子節點y->left = x->right;     // x的右子節點成為y的左子節點x->right = y;          // y成為x的右子節點// 更新高度x->height = 1 + max(height(x->left), height(x->right));y->height = 1 + max(height(y->left), height(y->right));return x;  // 新的根節點
}

?????????3.?左右旋是左旋和右旋的組合操作,發生在節點不平衡,且平衡因子大于1,同時右子節點的平衡因子小于0時。首先,對右子節點進行左旋,然后對整個樹以當前節點為根進行右旋。

? ? ? ? 4.?右左旋也是左旋和右旋的組合操作,但順序相反。它發生在節點不平衡,且平衡因子小于-1,同時左子節點的平衡因子大于0時。首先,對左子節點進行右旋,然后對整個樹以當前節點為根進行左旋。?

????????在實際應用中,當我們對AVL樹進行插入或刪除操作時,一旦導致樹不平衡,我們就需要根據節點及其子節點的平衡因子,決定執行哪種旋轉操作,來恢復樹的平衡。通過正確應用這四種旋轉操作,我們可以確保AVL樹始終保持平衡狀態,從而保持高效的性能。

????????需要注意的是,旋轉操作只是AVL樹維護平衡的一種方式,實際的應用場景中還需要處理其他情況,比如如何高效地查找節點、如何正確地插入和刪除節點等。但無論何種情況,保持樹的平衡都是AVL樹設計的核心所在。

????????AVL樹由于具有良好的平衡性,常被用于需要高效查找、插入和刪除操作的場景中,如數據緩存、關聯數組、文件系統等。它提供了一種高效的存儲和訪問數據的方式,特別是在數據量大、操作頻繁的情況下,AVL樹能夠保持較好的性能。

????????下面是一個簡單的AVL樹的C++實現,包含插入、刪除和打印樹的函數。代碼如下。

#include <iostream>
#include <stack>
#include <algorithm> 
using namespace std;// 定義AVL樹的節點結構體
struct AVLNode {int key;int height;AVLNode* left;AVLNode* right;AVLNode(int k) : key(k), height(1), left(nullptr), right(nullptr) {}
};// 查找樹中的最小值節點
AVLNode* minValueNode(AVLNode* node) {AVLNode* current = node;// 循環直到左孩子是nullptrwhile (current->left != nullptr)current = current->left;return current;
}// 獲取節點的高度
int getHeight(AVLNode* N) {if (N == nullptr)return 0;return N->height;
}// 獲取平衡因子
int getBalance(AVLNode* N) {if (N == nullptr)return 0;return getHeight(N->left) - getHeight(N->right);
}// 更新節點高度
void updateHeight(AVLNode* N) {if (N != nullptr)N->height = 1 + max(getHeight(N->left), getHeight(N->right));
}// 右旋
AVLNode* rightRotate(AVLNode* y) {AVLNode* x = y->left;AVLNode* T2 = x->right;x->right = y;y->left = T2;updateHeight(y);updateHeight(x);return x;
}// 左旋
AVLNode* leftRotate(AVLNode* x) {AVLNode* y = x->right;AVLNode* T2 = y->left;y->left = x;x->right = T2;updateHeight(x);updateHeight(y);return y;
}// 獲取插入新節點后的平衡AVL樹
AVLNode* insert(AVLNode* node, int key) {if (node == nullptr)return (new AVLNode(key));if (key < node->key)node->left = insert(node->left, key);else if (key > node->key)node->right = insert(node->right, key);else // Duplicate keys not allowedreturn node;// 更新高度updateHeight(node);// 獲取平衡因子int balance = getBalance(node);// 左左情況if (balance > 1 && key < node->left->key)return rightRotate(node);// 右右情況if (balance < -1 && key > node->right->key)return leftRotate(node);// 左右情況if (balance > 1 && key > node->left->key) {node->left = leftRotate(node->left);return rightRotate(node);}// 右左情況if (balance < -1 && key < node->right->key) {node->right = rightRotate(node->right);return leftRotate(node);}return node;
}// 從AVL樹中刪除一個節點
AVLNode* deleteNode(AVLNode* root, int key) {if (root == nullptr)return root;if (key < root->key)root->left = deleteNode(root->left, key);else if (key > root->key)root->right = deleteNode(root->right, key);else {// 節點有兩個子節點if (root->left && root->right) {AVLNode* temp = minValueNode(root->right);root->key = temp->key;root->right = deleteNode(root->right, temp->key);}// 節點只有一個子節點或沒有子節點else {AVLNode* temp = root->left ? root->left : root->right;if (temp == nullptr) {temp = root;root= nullptr;} else {*root = *temp;}free(temp);}}if (root == nullptr)return root;// 更新高度updateHeight(root);// 獲取平衡因子int balance = getBalance(root);// 右右情況if (balance > 1 && getBalance(root->left) >= 0)return rightRotate(root);// 左左情況if (balance < -1 && getBalance(root->right) <= 0)return leftRotate(root);// 左右情況if (balance > 1 && getBalance(root->left) < 0) {root->left = leftRotate(root->left);return rightRotate(root);}// 右左情況if (balance < -1 && getBalance(root->right) > 0) {root->right = rightRotate(root->right);return leftRotate(root);}return root;
}// 打印AVL樹(中序遍歷)
void inorder(AVLNode* root) {if (root != nullptr) {inorder(root->left);cout << root->key << " ";inorder(root->right);}
}// 主函數測試
int main() {AVLNode* root = nullptr;// 插入節點root = insert(root, 10);insert(root, 20);insert(root, 30);insert(root, 40);insert(root, 50);insert(root, 25);// 打印AVL樹cout << "所構建的AVL樹的中序遍歷是 \n";inorder(root);cout << endl;// 刪除節點root = deleteNode(root, 25);// 再次打印AVL樹cout << "刪除后修改的AVL樹的中序遍歷為 \n";inorder(root);cout << endl;return 0;
}

????????總的來說,AVL樹是一種非常有用的數據結構,它通過自動平衡保證了高效的查找、插入和刪除操作。掌握AVL樹的原理和操作對于理解數據結構和算法的重要性以及提高編程技能都非常有幫助。

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

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

相關文章

MongoDB基礎入門到深入(七)建模、調優

文章目錄 系列文章索引十一、MongoDB開發規范十二、MongoDB調優1、三大導致MongoDB性能不佳的原因2、影響MongoDB性能的因素3、MongoDB性能監控工具&#xff08;1&#xff09;mongostat&#xff08;2&#xff09;mongotop&#xff08;3&#xff09;Profiler模塊&#xff08;4&a…

K8S認證|CKA題庫+答案| 16. 升級集群

16、升級集群 CKA v1.29.0模擬系統免費下載試用&#xff1a; 百度網盤&#xff1a;https://pan.baidu.com/s/1vVR_AK6MVK2Jrz0n0R2GoQ?pwdwbki 題目&#xff1a; 您必須在以下Cluster/Node上完成此考題&#xff1a; Cluster Ma…

CTF網絡安全大賽簡單web題目:eval

題目來源于&#xff1a;bugku 題目難度&#xff1a;簡單 一道簡單web的題目 題目源代碼&#xff1a; <?phpinclude "flag.php";$a $_REQUEST[hello];eval( "var_dump($a);");show_source(__FILE__); ?> 這個PHP腳本有幾個關鍵部分&#xff0c;但…

太陽誘電:順應時代需求的新型電容器為何能在全球得到廣泛應用(下)

隨著汽車電動化和電子控制化的進展&#xff0c;車載計算機和電氣部件也在逐漸向大功率化的方向發展。而構成這些車載設備電源電路的電子元器件也必須隨之進行技術革新。太陽誘電集團攜手全資子公司ELNA&#xff0c;開發并供應新型電容器“導電性高分子混合鋁電解電容器”&#…

【熱門話題】一文帶你讀懂公司是如何知道張三在脈脈上發了“一句話”的

按理說呢&#xff0c;A公司和脈脈屬于不同的平臺&#xff0c;而且脈脈上大家可以匿名發言&#xff0c;所以&#xff0c;即便我坐在你邊上&#xff0c;我發了一句話上去&#xff0c;你也不知道是誰發的。但通過一些技術&#xff0c;我們卻可以分析出&#xff0c;公司是如何知道張…

IOC控制反轉

IOC IOC&#xff0c;全稱為Inversion of Control(控制反轉)&#xff0c;是一種設計原則&#xff0c;它反轉了傳統編程中的控制流程。在傳統的編程模式中&#xff0c;組件之間的依賴關系是由組件自身在內部創建和維護的。而在控制反轉模式中&#xff0c;這種依賴關系由外部容器(…

SSH 免密登錄vscode 附debug 免密登錄失敗問題排查

SSH 免密登錄vscode 附debug 關鍵詞 &#xff1a;vscode ssh ssh無法免密登錄 ssh免密登錄失敗 1 sshd 的配置文件/etc/ssh/sshd_config&#xff0c; 確保公鑰登錄開啟 PubkeyAuthentication yes2 生成公鑰并上傳 ssh-keygen找到本地 .ssh/id_rsa.pub 將其中文本內容搞到…

PS —— 制作證件照

PS —— 制作證件照 裁剪工具魔棒工具油漆桶工具擴展畫布 老是看編程&#xff0c;會有些疲勞&#xff0c;這個專欄我會放一些其他的知識&#xff0c;我們今天利用PS制作證件照&#xff08;注意&#xff0c;這里一些ps的基礎操作我不會很展開的去講&#xff09;&#xff1a; 裁…

Redisson分布式Redis鎖,tryLock方法詳解

在 Java 中&#xff0c;RLock 是 Redisson 庫中提供的一個分布式鎖接口&#xff0c;用于實現基于 Redis 的分布式鎖。RLock 的 tryLock 方法用于嘗試獲取鎖&#xff0c;并在特定的時間內等待獲取鎖。 方法簽名如下&#xff1a; boolean tryLock(long waitTime, long leaseTim…

WPF關鍵組件代碼示例

通過一個綜合示例代碼&#xff0c;展示WPF的關鍵組件&#xff0c;包括XAML、控件、數據綁定、樣式和模板以及動畫。這個示例創建一個簡單的WPF應用程序&#xff0c;包含一個文本框、按鈕和列表框&#xff0c;實現數據綁定、自定義樣式和模板&#xff0c;以及按鈕點擊后的動畫效…

深入解析R語言的貝葉斯網絡模型:構建、優化與預測;INLA下的貝葉斯回歸;現代貝葉斯統計學方法;R語言混合效應(多水平/層次/嵌套)

目錄 ①基于R語言的貝葉斯網絡模型的實踐應用 ②R語言貝葉斯方法在生態環境領域中的應用 ③基于R語言貝葉斯進階:INLA下的貝葉斯回歸、生存分析、隨機游走、廣義可加模型、極端數據的貝葉斯分析 ④基于R語言的現代貝葉斯統計學方法&#xff08;貝葉斯參數估計、貝葉斯回歸、…

react使用AntV

AntV使用&#xff08;https://antv.antgroup.com/&#xff09; import React, { useEffect } from "react"; // npm install antv/g2 import { Chart } from "antv/g2"; const Charts () > { function Ccc() { // 準備數據 const data [ { genre: …

【Linux】腳本shell script

shell是與Linux交互的基本工具 shell script是針對shell所寫的腳本&#xff0c;解釋執行&#xff0c;無需編譯 注意事項 指令的執行是從上而下、從左而右的分析與執行&#xff1b; 指令、選項與參數間的多個空白都會被忽略掉&#xff1b; 空白行也將被忽略掉&#xff0c;并且…

抽象工廠模式(AbstractFactoryPattern)

文章目錄 1.抽象工廠模式定義2.UML類圖3.抽象工廠模式具體實現工廠模式實現單一產品族抽象工廠實現多產品族產品類工廠類使用 4.抽象工廠模式優缺點 1.抽象工廠模式定義 提供一個創建一系列相關或相互依賴對象的接口&#xff0c;而無需指定它們具體的類。 工廠方法模式是單一產…

2024電工杯B題食譜評價與優化模型思路代碼論文分析

2024年電工杯數學建模競賽B題論文和代碼已完成&#xff0c;代碼為B題全部問題的代碼&#xff0c;論文包括摘要、問題重述、問題分析、模型假設、符號說明、模型的建立和求解&#xff08;問題1模型的建立和求解、問題2模型的建立和求解、問題3模型的建立和求解&#xff09;、模型…

正點原子[第二期]Linux之ARM(MX6U)裸機篇學習筆記-17講 定時器按鍵消抖

前言&#xff1a; 本文是根據嗶哩嗶哩網站上“正點原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸機篇”視頻的學習筆記&#xff0c;在這里會記錄下正點原子 I.MX6ULL 開發板的配套視頻教程所作的實驗和學習筆記內容。本文大量引用了正點原子教學視頻和鏈接中的內容。…

計算機網絡安全控制技術

1.防火墻技術 防火墻技術是近年來維護網絡安全最重要的手段&#xff0c;但是防火墻不是萬能的&#xff0c;需要配合其他安全措施來協同 2.加密技術 目前加密技術主要有兩大類&#xff1a;對稱加密和非對稱加密 3.用戶識別技術 核心是識別網絡者是否是屬于系統的合法用戶 …

【設計模式深度剖析】【1】【結構型】【代理模式】| 玩游戲打怪、升級為例加深理解

&#x1f448;?上一篇:創建型設計模式對比 | 下一篇:裝飾器模式&#x1f449;? 目 錄 代理模式定義英文原話直譯如何理解&#xff1f; 3個角色UML類圖1. 抽象主題&#xff08;Subject&#xff09;角色2. 代理類&#xff1a;代理主題&#xff08;Proxy Subject&#xff0…

UE5 OnlineSubsystem Steam創建會話失敗解決方法

連接上Steam但是創建會話失敗 解決方法 在DefaultEngine.ini中加上bInitServerOnClienttrue,這個其實在官方文檔里用注釋給出了&#xff0c;直接取消注釋就行 刪除項目目錄中的Saved、Internmediate、Binaries目錄 右鍵你的項目.uproject選擇Generate Visual Studio project f…

ASP.Net MVC在控制臺添加視圖時沒有模型類并且不能添加視圖

情況如下&#xff1a; 解決方法&#xff1a; 1.查看vs能否創建asp.net mvc項目&#xff0c;這種情況一般是更換了vs打開老項目 2.點擊跳轉至修改安裝選項界面 3.選擇安裝項即可 如果以上都有&#xff1a; 看看你的視圖文件是否存在在項目中 也不能點擊添加&#xff0c;如果…