数据结构与算法_AVL平衡二叉树_四种旋转,插入和删除
创始人
2024-02-20 21:18:44
0

1 AVL平衡二叉树的概念

平衡二叉树在BST树基础上加了平衡操作。
BST树特点 :在BST树的基础上,引入了节点“平衡”的概念,任意一个节点的左右子树高度差不超过 1 ,为了维持节点的平衡,引入了四种旋转操作,如下:
1.左孩子左子树太高,做右旋转操作
2.右孩子的右子树太高,做左旋转操作
3.左孩子的右子树太高,做左-右旋转操作(也叫左平衡操作)
4.右孩子的左子树太高,做右-左旋转操作(也叫右平衡操作)

AVL树:记忆的时候,与BST树的插入删除联系起来。
下面分别记录AVL的四种失衡操作,并举例说明。

2 AVL的四种旋转操作

2.1 右旋转

右旋转调整。如下图所示,40左子树高度为2,右子树高度为0 ,这种情况称为左失衡,需要进行右旋转。
在这里插入图片描述

2.2 左旋转

左旋转调整。当节点的右子树高度大于节点的左孩子高度时候,如下图情况,需要做左旋转调整。
调整方法:先记录当前节点的右孩子。然后,当前节点的右孩子指向当前节点孩子的左孩子;然后孩子节点的左孩子指向当前节点。
在这里插入图片描述

2.3 左右旋转

左右旋转,也叫左平衡调整。这种情况需要调整两次,先进行一次左旋转,再进行一次右旋转。如下图所示。
在这里插入图片描述

2.4 右左旋转

右左旋转,也称为有平衡操作。这种情况也需要调整两次,即先进行一次右旋转,再进行一次左旋转。
在这里插入图片描述

3 AVL的插入,旋转调整举例

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. BST树 和 AVL树插入1-10后,对比

BST树插入1-10后,BST树变成了一个链表;AVL树则是一颗平衡二叉树。
在这里插入图片描述

5. AVL四种旋转操作,插入,删除代码实现

#include 
#include 
using namespace std;// 定义AVL节点类型 
template 
class AVLTree
{
public:AVLTree() : root_(nullptr) { }// 插入操作void insert(const T &val){root_ = insert(root_, val);}// 删除操作void remove(const T & val){root_ = remove(root_, val);}private:// 定义AVL树节点类型 struct Node{Node(T data = T()):data_(data), left_(nullptr), right_(nullptr), height_(1){}T data_;Node *left_;Node *right_;int height_;};Node *root_;//int max(int a, int b){return a > b ? a : b;}/**	功能:返回node高度*/int height(Node *node){return node == nullptr ? 0 : node->height_;}/* *	功能:node节点进行右旋转,并返回旋转后的根节点**	参数:*		 node : 当前节点*	*   返回值: *		 返回旋转后的根节点*/Node *rightRotate(Node *node){Node *child = node->left_;node->left_ = child->right_;child->right_ = node;// 旋转后根节点和child节点发生了变化,所以要更新高度值。node->height_ = max(height(node->left_), height(node->right_)) + 1;node->height_ = max(height(child->left_), height(child->right_)) + 1;// 返回旋转后的根节点return child;}/*  功能:左旋转,并返回旋转后的根节点**	参数:*		 node : 根节点**   返回值:*		 返回旋转后的根节点*/Node *leftRotate(Node *node){Node *child = node->right_;node->right_ = child->left_;child->left_ = node;// 更新旋转后的高度值node->height_ = max(height(node->left_), height(node->right_)) + 1;child->height_ = max(height(child->left_), height(child->right_)) + 1;// 返回旋转后的根节点return child;}/**	功能:左右旋转,并把根节点返回**	参数:*		  node : 以参数node为旋转轴	*/		Node * leftBalance(Node *node){node->left_ = leftRotate(node->left_);  // 先对根节点左孩子进行左旋转return rightRotate(node);				// 再对,根节点右孩子进行右旋转。}/**	功能:右左旋转,并把根节点返回**	参数:*		  node : 以参数node为旋转轴*/Node * rightBalance(Node *node){node->right_ = rightRotate(node->right_);  // 以左孩子为根进行左旋return leftRotate(node);}/**	功能:node中插入节点,并返回新插入节点**/Node * insert(Node *node, const T & val){if (node == nullptr){return new Node(val);}if (node->data_ > val)   // 向当前节点的左子树中插入新节点,所以要判断,当前节点的左子树是否太高{node->left_ = insert(node->left_, val);  // 新插入的节点都在叶子节点上,所以下面回溯时,调整树的平衡状态。// 在回溯时候,判断节点是否失衡,如果node的左子树太高导致Node失衡了,// 当前在向左子树中插入节点,新节点在左子树的叶子中,只可能导致左子树失衡,不存在右子树失衡的情况,所以直接用左子树高度 减去 右子树高度。if (height(node->left_) - height(node->right_) > 1)  // 如果当前节点的左子树比右子树高{		 // 分两种情况来判断,一个是左孩子的左子树节点失衡,一个树右孩右子树节点失衡。if (height(node->left_->left_) >= height(node->left_->right_)){node = rightRotate(node);   // 用旋转后的根节点 代替根节点}else{node = leftBalance(node);}}}else if (node->data_ < val){node->right_ = insert(node->right_, val);// 在递归回溯时候,判断节点是否失衡,Node的右子树太高,node 失衡了if (height(node->right_) - height(node->left_) > 1){if (height(node->right_->right_) >= height(node->right_->left_))  // 1-10,插入节点9时会出现这种情况{node = leftRotate(node);}else{node = rightBalance(node);}}}else // 如果新插入节点与当前节点相等,不插入,不用再递归,直接回溯{;}// 更新节点高度。因为递归中增加了新节点,所以回溯时候,更新节点的高度。node->height_ = max(height(node->left_), height(node->right_)) + 1;return node; // rrturn后,直接回溯,不再向下递归}/**	功能:删除val节点**	参数:*		  node: 当前处理的根节点*		  val : 待删除的值*/Node * remove(Node *node,const T & val){if (node == nullptr){return nullptr;}if (node->data_ > val)    // 如果当前节点大于val,则从当前节点左孩子中查找{node->left_ = remove(node->left_, val);// 删除左子树的节点之后,可能造成右子树太高if (height(node->right_) - height(node->left_) > 1){// 右子树太高,分两种情况,第一:if (height(node->right_->right_) >= height(node->right_->left_)){// 右孩子的右子树太高node = leftRotate(node);}else{node = rightBalance(node);}}}else if (node->data_ < val){node->right_ = remove(node->right_, val);// 删除右节点后,可能造成左子树太高if (height(node->left_) - height(node->right_) > 1){// 如果左孩子的左子树失衡if (height(node->left_->left_) >= height(node->left_->right_)){node = rightRotate(node);}else{node = leftBalance(node);}}}else  // 删除节点,先删除两个孩子的节点,再删除一个孩子的节点{// 找到后,先处理两个孩子的节点,然后再删除一个孩子的节点。if (node->left_ != nullptr && node->right_ != nullptr){// 为了避免删除前驱和后继节点造成节点失衡,she高删除谁if (height(node->left_) >= height(node->right_)){// 删除	前驱Node *pre = node->left_;while (pre->right_ != nullptr){pre = pre->right_;}node->data_ = pre->data_;						// 覆盖值node->left_ = remove(node->left_, pre->data_);  // 删除前驱节点}else{// 删除后继节点Node *post = node->right_;while (post->right_ != nullptr){post = post->left_;}node->data_ = post->data_;node->right_ = remove(node->right_, post->data_);  // 删除后继节点}}else  // 最多有一个孩子节点{if (node->left_ != nullptr){Node *left = node->left_;delete node;return left;}else if (node->right_ != nullptr){Node *right = node->right_;delete node;return right;}else{return nullptr;}}}// 更新节点高度node->height_ = max(height(node->left_), height(node->right_)) + 1;return node;}
};int main()
{AVLTree avl;for (int i = 1; i < 11; i++){avl.insert(i);}avl.remove(6);system("pause");return 0;
}

相关内容

热门资讯

迎江区2025年刑事法律援助工... 12月12日下午,迎江区司法局牵头召开2025年刑事法律援助工作联席会议,迎江公安分局、区检察院、区...
天津市城市更新条例 天津市城市更新条例 (2025年11月28日天津市第十八届人民代表大会常务委员会第二十二次会议通过)...
专家:资本市场将加快完善中长期... 中国证监会日前召开党委(扩大)会议,传达学习贯彻中央经济工作会议精神,研究部署了五方面重点工作。业内...
特朗普起诉BBC 索赔50亿美... 据央视新闻消息,央视记者当地时间15日获悉,美国总统特朗普正式起诉英国广播公司(BBC),索赔50亿...
流感、带状疱疹、HPV疫苗优惠... 记者从市卫健委获悉, 按照黑龙江省疾病预防控制局统一部署,为切实守护好市民健康,哈尔滨市卫生健康委员...
特朗普起诉BBC诽谤。(POL... 特朗普起诉BBC诽谤,寻求向BBC索赔至少50亿美元。(Politico)
国家外汇管理局:稳步扩大外汇领... 近日,国家外汇管理局党组书记、局长朱鹤新主持召开党组(扩大)会议,传达学习中央经济工作会议精神,结合...
【专家称明年财政政策“工具箱”... 【专家称明年财政政策“工具箱”有望进一步扩容】展望2026年,财政政策在制定与执行的过程中将紧密结合...
2026年重点推动生育保险发展... 12月13日,全国医疗保障工作会议上释放的信息提到,2026年要重点推动生育保险发展,“力争做到让孕...
明年财政政策“工具箱”有望进一... 回顾2025年,更加积极的财政政策在保障国家重大战略实施,扩内需、稳增长、惠民生方面取得积极成效。展...