欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > AVL树解析

AVL树解析

2025/5/12 13:34:26 来源:https://blog.csdn.net/nplplus/article/details/147875146  浏览:    关键词:AVL树解析

插入操作
  

// 插入操作
bool insert(const pair<K, V>& kv)
{// 若树为空,直接构造,new一个if (_root == nullptr) {_root = new Node(kv);return true;}// 用于遍历树的当前节点Node* cur = _root;// 用于记录当前节点的父节点Node* parent = nullptr;// 循环查找插入位置while (cur) {// 插入值大于当前节点值,向右移动if (cur->_kv.first < kv.first) {parent = cur;cur = cur->_kv.first;}// 插入值小于当前节点值,向左移动else if (cur->_kv.first > kv.first) {parent = cur;cur = cur->_left;}// 插入值等于当前节点值,去重else {return false;}}// 跳出循环后,cur指向空,创建新节点cur = new Node(kv);// 根据父节点的值决定新节点是父节点的左子节点还是右子节点if (parent->_kv.first < kv.first) {parent->_right = cur;}else {parent->_left = cur;}// 设置新节点的父节点cur->_parent = parent;// 控制平衡while (parent) {// 右加左减 if (cur == parent->_left) {parent->_bf--;}else {parent->_bf++;}// 平衡因子为0,说明子树平衡,跳出循环if (parent->_bf == 0) {break;}// 平衡因子为1或-1,说明子树仍平衡,继续向上更新else if (parent->_bf == 1 || parent->_bf == -1) {// 继续更新cur = parent;parent = parent->_parent;}// 平衡因子为2或-2,说明子树不平衡,需要旋转else if (parent->_bf == 2 || parent->_bf == -2) {// 根据节点的平衡因子决定旋转类型if (parent->_bf == 2 && cur->_bf == 1) {RotateL(parent);}else if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}else if (parent->_bf == 2 && cur->_bf == -1){RotateRL(parent);}else if (parent->_bf == -2 && cur->_bf == 1){RotateLR(parent);}}else {assert(false);}}return true;
}


 
1. 函数功能概述:这个函数的主要功能是向树中插入一个新的键值对 kv ,并且在插入后通过旋转操作来维护树的平衡。
 
2. 树为空的情况:
 
-  if (_root == nullptr) :检查树是否为空。如果为空,创建一个新的节点并将其设置为根节点,然后返回 true ,表示插入成功。
 
3. 查找插入位置:
 
- 使用 while (cur) 循环来遍历树,根据当前节点的值与插入值的大小关系,决定是向左还是向右移动。
 
- 如果插入值等于当前节点的值,返回 false ,表示插入失败(去重操作)。
 
4. 插入新节点:
 
- 循环结束后, cur 指向空,创建一个新的节点并将其插入到合适的位置(作为父节点的左子节点或右子节点),并设置新节点的父节点。
 
5. 维护树的平衡:
 
- 使用 while (parent) 循环向上更新节点的平衡因子。
 
- 根据新节点是父节点的左子节点还是右子节点,更新父节点的平衡因子。
 
- 如果平衡因子为0,说明子树平衡,跳出循环。
 
- 如果平衡因子为1或-1,继续向上更新。
 
- 如果平衡因子为2或-2,根据节点的平衡因子决定进行哪种旋转操作(左旋 RotateL 、右旋 RotateR 、先左后右双旋 RotateRL 、先右后左双旋 RotateLR )。
 
6. 返回值:最后返回 true ,表示插入操作成功。
 
这段代码主要实现了在平衡二叉树(如AVL树)中插入节点并维护树的平衡的功能。不过,代码中存在一些小错误,例如 cur = cur->_kv.first 这一行应该是 cur = cur->_right ,可能是笔误。同时,代码中使用的 RotateL 、 RotateR 、 RotateRL 和 RotateLR 函数的具体实现也需要根据实际情况进行补充。

//左转void RotateL(Node* parent) {Node* cur = parent->_right;Node* curleft = cur->_left;parent->_right = curleft;if (curleft){curleft->_parent = parent;}cur->_left = parent;Node* ppnode = parent->_parent;parent->_parent = cur;if (parent == _root) {_root = cur;cur->_parent = nullptr;}else {if (ppnode->_left == parent) {ppnode->_left = cur;}else {ppnode->_parent= cur;}cur->_parent = ppnode;}parent->_bf = cur->_bf = 0;}

以下是对这段代码  RotateL (左旋操作)的详细解析:
 
1. 函数声明:
 
  

void RotateL(Node* parent) 


 
 
这是一个名为  RotateL  的函数,它接受一个指向  Node  类型的指针  parent  作为参数,函数的返回值类型为  void ,即不返回任何值。 parent  表示要进行左旋操作的节点。
 
1. 变量定义:
 
  

Node* cur = parent->_right;
Node* curleft = cur->_left;


 
定义了两个指针变量  cur  和  curleft 。 cur  指向  parent  的右子节点, curleft  指向  cur  的左子节点。这里的操作是为左旋操作做准备,获取相关节点的指针以便后续调整指针指向。
 
1. 调整  parent  的右子节点:
 
  

parent->_right = curleft;
if (curleft)
{curleft->_parent = parent;
}


 
 
将  parent  的右子节点设置为  curleft 。如果  curleft  不为空(即  cur  原本有左子节点),则将  curleft  的父节点设置为  parent 。这一步是为了重新连接  parent  和  curleft  之间的父子关系。
 
1. 调整  cur  的左子节点:
 
  

cur->_left = parent;


 
 
将  cur  的左子节点设置为  parent ,这是左旋操作中改变指针指向的关键步骤之一,使得  parent  成为  cur  的左子节点。
 
1. 处理  parent  的父节点:
 
 

Node* ppnode = parent->_parent;
parent->_parent = cur;


 
定义了一个指针  ppnode  指向  parent  的父节点。然后将  parent  的父节点设置为  cur ,这一步是为了更新  parent  的父节点信息,使其指向  cur 。
 
1. 处理根节点情况:
 
  

if (parent == _root) 
{_root = cur;cur->_parent = nullptr;
}


 
 
如果  parent  是根节点(即  parent  是整个树的根),则将根节点  _root  指向  cur ,并将  cur  的父节点设置为  nullptr ,这是因为  cur  成为了新的根节点,它没有父节点。
 
1. 处理非根节点情况:
 
  

else 
{if (ppnode->_left == parent) {ppnode->_left = cur;}else {ppnode->_parent= cur;}cur->_parent = ppnode;
}


 
 
如果  parent  不是根节点,则根据  parent  是  ppnode  的左子节点还是右子节点,相应地将  ppnode  的左子节点或右子节点设置为  cur 。最后将  cur  的父节点设置为  ppnode ,确保  cur  与  ppnode  之间的父子关系正确。
 
1. 设置平衡因子:
 
  

parent->_bf = cur->_bf = 0;


 
 
将  parent  和  cur  的平衡因子  _bf  都设置为 0,这是在左旋操作完成后对平衡因子的更新,因为左旋操作可能会影响节点的平衡状态,这里简单地将它们的平衡因子设为 0,具体的平衡因子计算可能需要根据树的其他信息进一步处理。
 
 

    

//右转void RotateR(Node* parent){Node* cur = parent->_left;Node* curright = cur->_right;parent->_left= curright;if (curright){curright->_parent = parent;}cur->_right= parent;Node* ppnode = parent->_parent;cur->_right = parent;if (ppnode==nullptr){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right= cur;}cur->_parent = ppnode;}parent->_bf = cur->_bf = 0;}

以下是对这段  RotateR (右转操作)代码的详细解析:
 
1. 函数声明:
 

  

void RotateR(Node* parent) 


 
 
这是一个名为  RotateR  的函数,接收一个指向  Node  类型的指针  parent  作为参数,函数返回值类型为  void ,即不返回任何值。 parent  表示要进行右转操作的节点。
 
1. 变量定义:
 

  

Node* cur = parent->_left;
Node* curright = cur->_right;


 
 
定义了两个指针变量  cur  和  curright 。 cur  指向  parent  的左子节点, curright  指向  cur  的右子节点。这是为右转操作做准备,获取相关节点的指针以便后续调整指针指向。
 
1. 调整  parent  的左子节点:
 

  

parent->_left = curright;
if (curright)
{curright->_parent = parent;
}


 
将  parent  的左子节点设置为  curright 。如果  curright  不为空(即  cur  原本有右子节点),则将  curright  的父节点设置为  parent 。这一步是为了重新连接  parent  和  curright  之间的父子关系。
 
1. 调整  cur  的右子节点:
 
 

  
cur->_right = parent;


 
 
将  cur  的右子节点设置为  parent ,这是右转操作中改变指针指向的关键步骤之一,使得  parent  成为  cur  的右子节点。
 
1. 处理  parent  的父节点:
 

  

Node* ppnode = parent->_parent;


 
 
定义了一个指针  ppnode  指向  parent  的父节点。
 
1. 处理根节点情况:
 
  

if (ppnode == nullptr) 
{_root = cur;cur->_parent = nullptr;
}


 
 
如果  ppnode  为空(即  parent  原本是根节点),则将根节点  _root  指向  cur ,并将  cur  的父节点设置为  nullptr ,因为  cur  成为了新的根节点,它没有父节点。
 
1. 处理非根节点情况:
 

  

else 
{if (ppnode->_left == parent) {ppnode->_left = cur;}else {ppnode->_right = cur;}cur->_parent = ppnode;
}


 
 
如果  ppnode  不为空(即  parent  不是根节点),根据  parent  是  ppnode  的左子节点还是右子节点,相应地将  ppnode  的左子节点或右子节点设置为  cur 。最后将  cur  的父节点设置为  ppnode ,确保  cur  与  ppnode  之间的父子关系正确。
 
1. 设置平衡因子:
 
 

  
parent->_bf = cur->_bf = 0;


 
 
将  parent  和  cur  的平衡因子  _bf  都设置为 0,这是在右转操作完成后对平衡因子的更新,因为右转操作可能会影响节点的平衡状态,这里简单地将它们的平衡因子设为 0,具体的平衡因子计算可能需要根据树的其他信息进一步处理。
 
 

  

  //右左双旋void RotateRL(Node* parent){Node* cur = parent->_right;Node* curleft = cur->_left;int bf = curleft->_bf;RotateR(parent->_right);RotateL(parent);if (bf == 0){cur->_bf = 0;curleft->_bf = 0;parent->_bf = 0;}else if (bf == 1){cur->_bf = 0;curleft->_bf = 0;parent->_bf = -1;}else if (bf == -1){cur->_bf = 1;curleft->_bf = 0;parent->_bf = 0;}else{assert(false);}}

    以下是对  RotateRL  函数(右左双旋操作)的详细解析:
 
1. 函数声明:
 
  
void RotateRL(Node* parent)
 
 
这是一个名为  RotateRL  的函数,接受一个指向  Node  类型的指针  parent  作为参数,函数的返回值类型为  void ,即不返回任何值。 parent  表示要进行右左双旋操作的节点。
 
1. 变量定义:
 
  
Node* cur = parent->_right;
Node* curleft = cur->_left;
int bf = curleft->_bf;
 
 
定义了三个变量。 cur  指向  parent  的右子节点, curleft  指向  cur  的左子节点, bf  用于存储  curleft  的平衡因子  _bf 。这些操作是为后续的双旋操作获取相关节点的信息和平衡因子。
 
1. 第一次旋转(右旋):
 
 

RotateR(parent->_right);


 
 
调用  RotateR  函数(右旋函数),对  parent  的右子节点进行右旋操作。右旋操作会调整树的结构,改变节点之间的指针指向。
 
1. 第二次旋转(左旋):
 

RotateL(parent);


 
 
调用  RotateL  函数(左旋函数),对  parent  进行左旋操作。左旋操作同样会调整树的结构,改变节点之间的指针指向。经过先右旋再左旋的操作,实现了右左双旋,对树的整体结构进行了调整。
 
1. 更新平衡因子:
 

if (bf == 0)
{cur->_bf = 0;curleft->_bf = 0;parent->_bf = 0;
}
else if (bf == 1)
{cur->_bf = 0;curleft->_bf = 0;parent->_bf = -1;
}
else if (bf == -1)
{cur->_bf = 1;curleft->_bf = 0;parent->_bf = 0;
}
else
{assert(false);
}


 
根据之前保存的  curleft  的平衡因子  bf  的值,来更新  cur 、 curleft  和  parent  的平衡因子。
- 当  bf  为  0  时,将  cur 、 curleft  和  parent  的平衡因子都设为  0 ,表示这些节点在双旋操作后达到了平衡状态。
- 当  bf  为  1  时,将  cur  和  curleft  的平衡因子设为  0 ,将  parent  的平衡因子设为  -1 ,更新它们的平衡因子以反映双旋后的状态。
- 当  bf  为  -1  时,将  cur  的平衡因子设为  1 , curleft  的平衡因子设为  0 , parent  的平衡因子设为  0 ,调整它们的平衡因子。
- 如果  bf  不是上述的  0 、 1 、 -1  这几种情况,通过  assert(false)  来触发断言,通常意味着出现了异常情况,因为正常情况下平衡因子应该是这几个值之一。
 
 

//左右双旋void RotateLR(Node* parent){Node* cur = parent->_left;Node* curright = cur->_right;int bf = curright->_bf;RotateL(parent->_left);RotateR(parent);if (bf == 0){cur->_bf = 0;curleft->_bf = 0;parent->_bf = 0;}else if (bf == 1){cur->_bf = -1;curleft->_bf = 0;parent->_bf = 0;}else if (bf == -1){cur->_bf = 0;curleft->_bf = 0;parent->_bf = 1;}else{assert(false);}}

以下是对  RotateLR  函数(左右双旋操作)的详细解析:
 
1. 函数声明:
 
 

void RotateLR(Node* parent)


 
 
该函数名为  RotateLR ,接受一个指向  Node  类型的指针  parent  作为参数,返回值类型为  void ,即不返回任何值。 parent  是要进行左右双旋操作的节点。
 
1. 变量定义:
 

  
Node* cur = parent->_left;
Node* curright = cur->_right;
int bf = curright->_bf;


 
 
定义了三个变量。 cur  指向  parent  的左子节点; curright  指向  cur  的右子节点; bf  用于存储  curright  的平衡因子  _bf 。这些操作是为后续的双旋操作获取相关节点的信息和平衡因子。
 
1. 第一次旋转(左旋):
 
  

RotateL(parent->_left);


 
 
调用  RotateL  函数(左旋函数),对  parent  的左子节点进行左旋操作。左旋操作会改变树的结构,调整节点之间的指针指向。
 
1. 第二次旋转(右旋):
 
 

RotateR(parent);


 
 
调用  RotateR  函数(右旋函数),对  parent  进行右旋操作。右旋操作同样会调整树的结构,改变节点之间的指针指向。先左旋再右旋的操作,实现了左右双旋,对树的整体结构进行调整。
 
1. 更新平衡因子:
 
  

if (bf == 0)
{cur->_bf = 0;// 这里原代码应该是curright->_bf = 0,可能是笔误,按逻辑应该是这个节点的平衡因子设为0curright->_bf = 0; parent->_bf = 0;
}
else if (bf == 1)
{cur->_bf = -1;curright->_bf = 0;parent->_bf = 0;
}
else if (bf == -1)
{cur->_bf = 0;curright->_bf = 0;parent->_bf = 1;
}
else
{assert(false);
}


 
 
根据之前保存的  curright  的平衡因子  bf  的值,来更新  cur 、 curright  和  parent  的平衡因子:
- 当  bf  为  0  时,将  cur 、 curright  和  parent  的平衡因子都设为  0 ,表示这些节点在双旋操作后达到了平衡状态。
- 当  bf  为  1  时,将  cur  的平衡因子设为  -1 , curright  的平衡因子设为  0 , parent  的平衡因子设为  0 ,更新它们的平衡因子以反映双旋后的状态。
- 当  bf  为  -1  时,将  cur  的平衡因子设为  0 , curright  的平衡因子设为  0 , parent  的平衡因子设为  1 ,调整它们的平衡因子。
- 如果  bf  不是上述的  0 、 1 、 -1  这几种情况,通过  assert(false)  来触发断言,意味着出现了异常情况,因为正常情况下平衡因子应该是这几个值之一。
 

完整代码 

#include<iostream>
#include<assert.h>
using namespace std;
template<class K,class V>
struct AVLTreeNode
{pair<K, V>_kv;AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;int _bf;AVLTreeNode(const pair<K, V>& kv):_kv(kv),_left(nullptr),_right(nullptr),_parent(nullptr),_bf(0){}
};template<class K, class V>
class AVLTree
{typedef AVLTreeNode<K, V>Node;
public://插入操作bool insert(const pair<K, V>& kv){if (_root == nullptr) //若树为空,直接构造,new一个{_root = new Node(kv);return true;}Node* cur = _root;Node* parent = nullptr;while (cur) {if (cur->_kv .first< kv.first)//插入值大于root右移{parent = cur;cur = cur->_right;}else if (cur->_kv.first> kv.first)//插入值小于root左移{parent = cur;cur = cur->_left;}else //相等去重{return false;}}//跳空判断cur的位置cur = new Node(kv);if (parent->_kv.first < kv.first) {parent->_right = cur;}else {parent->_left = cur;}cur->_parent = parent;//...控制平衡//更新平衡while (parent) {//右加左减 if (cur = parent->_left) {parent->_bf--;}else {parent->_bf++;}if (parent->_bf == 0) {break;}else if (parent->_bf == 1 || parent->_bf == -1) {//继续更新cur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2) {//子树不平衡,需要旋转if (parent->_bf == 2 && cur->_bf == 1) {RotateL(parent);}else if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}else if (parent->_bf == 2 && cur->_bf == -1){RotateRL(parent);}else if (parent->_bf == -2 && cur->_bf == 1){RotateLR(parent);}}else {assert(false);}}return true;}//左转void RotateL(Node* parent) {Node* cur = parent->_right;Node* curleft = cur->_left;parent->_right = curleft;if (curleft){curleft->_parent = parent;}cur->_left = parent;Node* ppnode = parent->_parent;parent->_parent = cur;if (parent == _root) {_root = cur;cur->_parent = nullptr;}else {if (ppnode->_left == parent) {ppnode->_left = cur;}else {ppnode->_parent= cur;}cur->_parent = ppnode;}parent->_bf = cur->_bf = 0;}//右转void RotateR(Node* parent){Node* cur = parent->_left;Node* curright = cur->_right;parent->_left= curright;if (curright){curright->_parent = parent;}cur->_right= parent;Node* ppnode = parent->_parent;cur->_right = parent;if (ppnode==nullptr){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right= cur;}cur->_parent = ppnode;}parent->_bf = cur->_bf = 0;}//右左双旋void RotateRL(Node* parent){Node* cur = parent->_right;Node* curleft = cur->_left;int bf = curleft->_bf;RotateR(parent->_right);RotateL(parent);if (bf == 0){cur->_bf = 0;curleft->_bf = 0;parent->_bf = 0;}else if (bf == 1){cur->_bf = 0;curleft->_bf = 0;parent->_bf = -1;}else if (bf == -1){cur->_bf = 1;curleft->_bf = 0;parent->_bf = 0;}else{assert(false);}}//左右双旋void RotateLR(Node* parent){Node* cur = parent->_left;Node* curright = cur->_right;int bf = curright->_bf;RotateL(parent->_left);RotateR(parent);if (bf == 0){cur->_bf = 0;curleft->_bf = 0;parent->_bf = 0;}else if (bf == 1){cur->_bf = -1;curleft->_bf = 0;parent->_bf = 0;}else if (bf == -1){cur->_bf = 0;curleft->_bf = 0;parent->_bf = 1;}else{assert(false);}}private:Node* _root=nullptr;
};

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词