[Structure des données] Insertion et vérification de l'arborescence AVL

1. Notions de base

1. Contexte du développement

  • Les arbres de recherche binaires ordinaires dégénéreront en une forme semblable à une liste chaînée dans des cas extrêmes, réduisant ainsi l'efficacité de la recherche à O(N) .

  • Sur cette base, le mathématicien soviétique et israélien ADelson- VElskii et le mathématicien soviétique LAndis ont inventé l'arbre AVL ou arbre de recherche binaire équilibré.

Insérer la description de l'image ici
Insérer la description de l'image ici

Remarque : la première photo-Adelson-Velskii (1922-2014), la deuxième photo-Landis (1921-1997)

2. Nature

  • La valeur absolue de la différence de hauteur entre les sous-arbres gauche et droit n'est pas supérieure à 1
  • Chaque sous-arbre est un arbre AVL.

Remarque : le but est de contrôler strictement l'équilibre pour améliorer l'efficacité de la recherche, mais il est impossible de contrôler la différence de hauteur pour qu'elle soit toujours égale à 0. Quant à savoir pourquoi elle ne peut pas être contrôlée à 0, en supposant qu'il doit y avoir une différence de hauteur de 1 entre seulement deux nœuds.

2. Principe de mise en œuvre

①Opération d'insertion

1. Facteur d'équilibre

Nom français : facteur d'équilibre

  • But:保证左右子树的高度差的绝对值不大于1
  • La plupart des implémentations :存放的是右子树与左子树的高度差

1.1 Mise à jour du facteur d'équilibre

1.1.1 Modifications de la hauteur des arbres

① Ajouter un nouveau nœud à gauche
Insérer la description de l'image ici

② Ajoutez un nouveau nœud à droite

Insérer la description de l'image ici

  • Résumer
  1. Nouvellement ajouté à gauche, le facteur d'équilibre du nœud racine est réduit de 1
  2. Nouvellement ajouté à droite, le facteur d'équilibre du nœud racine est augmenté de 1
  3. Le facteur d'équilibre passe de 0 à 1 ou -1

Continuez l'analyse :
 deux situations d'arbres 高度增加1, c'est-à-dire que 平衡因子从0变为1或者-1puisque la hauteur change, cela peut provoquer un déséquilibre de l'arbre supérieur.
comme:
Insérer la description de l'image ici

À ce stade, nous devons mettre à jour le facteur d'équilibre à la hausse, puis décider d'ajouter 1 ou de soustraire 1 au facteur d'équilibre de la racine en fonction du changement de hauteur à droite et de la hauteur à gauche.

  • inférence:由于可能会向上更新平衡因子,那么AVL树是三叉链的结构。

Comme le montre l'image :
Insérer la description de l'image ici

1.1.2 La hauteur de l'arbre reste inchangée

① Ajouter un nouveau nœud à gauche

Insérer la description de l'image ici
② Ajoutez un nouveau nœud à droite

Insérer la description de l'image ici

  • Même raison
  1. Nouvellement ajouté à gauche, le facteur d'équilibre du nœud racine est réduit de 1
  2. Nouvellement ajouté à droite, le facteur d'équilibre du nœud racine est augmenté de 1
  3. Le facteur d'équilibre passe de 1 ou -1 à 0

En poursuivant l'analyse, la hauteur de l'arbre où se trouve le nœud racine est——左右子树高度的最大值 + 1(根节点的高度)

Si la valeur maximale de la hauteur des sous-arbres gauche et droit reste inchangée, c'est-à-dire que la hauteur de l'arbre reste inchangée, c'est-à-dire que l' 不用往上继续更新équilibre est atteint.

2. Rotation

  • Explication : Rotation signifie laisser 不平衡的树再次平衡的手段.

  • Condition : Le facteur d'équilibre est de 2 ou -2, c'est-à-dire que la valeur absolue de la différence de hauteur est de 2.

  • Supplément : Si le facteur d'équilibre est supérieur ou égal à 3, cela signifie que l'arbre actuel n'est pas un arbre AVL, et le code précédent doit être vérifié.

Mais nous devons classer à nouveau les situations , car différentes situations nécessitent différentes manières de faire tourner l'arbre pour le rééquilibrer.

2.1Gaucher

  • Explication : c'est-à-dire que la hauteur du côté droit est élevée et qu'il faut la faire pivoter pour abaisser la hauteur du côté droit afin d'atteindre l'équilibre.

Analysons-le étape par étape, en commençant par le plus simple :

Insérer la description de l'image ici
À ce stade, les facteurs d’équilibre deviennent tous 0 après la rotation et l’arbre actuel atteint l’équilibre. 注意此时3结点的左结点为空!(détail)

Donnons un autre exemple :

Insérer la description de l'image ici

À ce moment-là, les facteurs d'équilibre des facteurs d'équilibre 1 et 3 deviennent 0 après la rotation et l'arbre actuel atteint l'équilibre 不用管其它子树的,因为子树必然是AVL树,要不然更不到根节点就停止了.

Enfin, prenons un exemple un peu plus compliqué :
Insérer la description de l'image ici
à ce moment, le facteur d'équilibre de -5 et 0 devient 0 après rotation, et l'arbre actuel est équilibré.

Il s’agit d’une image concrète pour faciliter la compréhension, puis nous dessinons une image abstraite de toutes les situations :
Insérer la description de l'image ici

  • Résumer
  1. 只能L'insertion d'un nœud sur la pièce c peut provoquer 根节点une rotation vers la gauche, c'est-à-dire parent的右边为cur且新增结点在cur的右边.
  2. Après rotation cur与parent的平衡因子变为0.
  • détail
  1. Lorsque le nœud parent de b est connecté au parent, il doit déterminer si la partie b est vide.
  2. Lorsque le nœud parent de parent est connecté à cur, le nœud parent de parent doit être enregistré.
  3. Déterminez si le nœud racine doit être modifié en fonction du nœud parent. S'il est vide, modifiez-le. S'il n'est pas vide, liez cur au nœud parent de parent et mettez à jour le pointage du nœud parent.
  • Implémenter le code
	void RotateL(Node* parent)
	{
    
    
		//画图分析:
		//操作的结点有cur,cur_left,ppnode
		Node* cur = parent->_right;
		Node* cur_left = cur->_left;
		//将parent的右节点改为cur_left
		parent->_right = cur_left;
		//改变cur_left父节点的转向
		//cur_left可能为空
		if (cur_left != nullptr)
		{
    
    
			cur_left->_parent = parent;
		}
		//将parent链接在cur的左边
		//为了更新cur的parent需要保存parent的父节点
		Node* ppnode = parent->_parent;

		cur->_left = parent;
		parent->_parent = cur;

		//ppnode可能为空
		if (ppnode == nullptr)
		{
    
    
			//需要修改根节点
			_root = cur;
			cur->_parent = nullptr;
		}
		else
		{
    
    
			//改变ppnode的指向
			if (ppnode->_left == parent)
			{
    
    
				ppnode->_left = cur;
			}
			else
			{
    
    
				ppnode->_right = cur;
			}
			cur->_parent = ppnode;

		}

		//更新平衡因子
		cur->_bf = parent->_bf = 0;

	}

2.2 Rotation à droite

Explication : c'est-à-dire que la hauteur du côté gauche est élevée et qu'il faut la faire pivoter pour réduire la hauteur du côté droit afin d'atteindre l'équilibre.

Elle s’analyse de la même manière que la rotation à gauche.

Ayons d’abord un sentiment simple :

Insérer la description de l'image ici

À ce stade, les facteurs d'équilibre du parent et du cur deviennent 0 après la rotation et l'arbre actuel atteint l'équilibre.

Autre exemple :
Insérer la description de l'image ici
Enfin, prenons un exemple un peu plus compliqué :
Insérer la description de l'image ici

Dessinez des diagrammes abstraits de toutes les situations :

Insérer la description de l'image ici

  • Résumer
  1. 只能L'insertion d'un nœud sur la pièce a peut provoquer 根节点une monorotation à droite, c'est-à-direparent与cur与高度变化的c树的根节点在同一个方向且在parent的左
  2. Après rotation cur与parent的平衡因子变为0.

  • Détails - Identique à la rotation à gauche
  1. Lorsque le nœud parent de b est connecté au parent, il doit déterminer si la partie b est vide.
  2. Lorsque le nœud parent de parent est connecté à cur, le nœud parent de parent doit être enregistré.
  3. Déterminez si le nœud racine doit être modifié en fonction du nœud parent. S'il est vide, modifiez-le. S'il n'est pas vide, liez cur au nœud parent de parent et mettez à jour le pointage du nœud parent.
  • Code d'implémentation :
		void RotateR(Node* parent)
		{
    
    
			//操作的结点
			Node* cur = parent->_left;
			Node* cur_right = cur->_right;

			//第一步:将cur_right链接到parent的left
			parent->_left = cur_right;
			//更改cur_right的父节点
			//注意:cur_right可能为空
			if (cur_right != nullptr)
			{
    
    
				cur_right->_parent = parent;
			}
			//第二步:将parent链接到cur的右结点。
			//先保存一下parent的父节点
			Node* ppnode = parent->_parent;

			cur->_right = parent;
			parent->_parent = cur;
			//ppnode为空说明需要修改根节点
			if (ppnode == nullptr)
			{
    
    
				_root = cur;
				cur->_parent = nullptr;
			}
			else
			{
    
    
				if (ppnode->_left == parent)
				{
    
    
					ppnode->_left = cur;
				}
				else
				{
    
    
					ppnode->_right = cur;
				}

				cur->_parent = ppnode;
			}
			
			//更新平衡因子
			cur->_bf = parent->_bf = 0;

		}

2.3 Rotation double droite et gauche

  • Cela peut être simplement compris comme une rotation à gauche qui doit être traitée.

Remarque : une seule rotation ne peut pas résoudre le problème car elle 发生了拐弯doit être utilisée 右旋讲折线变为直线,再进行左旋.

Parce qu’il existe de nombreuses situations, réalisons un schéma abstrait simple et direct afin que la conclusion soit plus facile à comprendre.

Faisons d'abord une chose simple :
Insérer la description de l'image ici
faites d'abord une rotation à droite, puis la polyligne devient une ligne droite, puis elle devient une forme à gauche, puis tournez à gauche. Enfin, le facteur d'équilibre de cur, cur_left et parent devient 0, et finalement cur_left devient le nœud racine.

Image de ré-abstraction :

Etat initial
Insérer la description de l'image ici

Insérer la description de l'image ici
C’est toujours pareil, mais il y a deux situations à discuter :

  1. L'ajout d'un nouveau nœud au c-tree fera passer le facteur d'équilibre du parent à -1 et le facteur d'équilibre de cur à 0.
  2. L'ajout d'un nouveau nœud au b-tree fera passer le facteur d'équilibre du parent à 0 et le facteur d'équilibre de cur à 1.
  3. Peu importe sur qui se trouve le nouveau nœud, le facteur d'équilibre de cur_left est de 0.
  • En regardant l'analyse graphique, en fait, peu importe sur qui se trouve le nouveau nœud, les résultats des deux rotations finales sont les mêmes. Il suffit alors de dessiner le graphique sans regarder le nouveau nœud, puis d'ajouter le nouveau nœud basé sur le résultat final. Cliquer dessus le rendra en fait plus intuitif.

  • Résumer

  1. L'ajout d'un nouveau nœud au c-tree fera passer le facteur d'équilibre du parent à -1 et le facteur d'équilibre de cur à 0.
  2. L'ajout d'un nouveau nœud au b-tree fera passer le facteur d'équilibre du parent à 0 et le facteur d'équilibre de cur à 1.
  3. Cur_left est un nouveau nœud et les nœuds de parent et cur sont tous 0.
  • Code d'implémentation :
	void RotateRL(Node* parent)
	{
    
    
		Node* cur = parent->_right;
		Node* cur_left = cur->_left;

		//CL——CurLeft
		int CL_bf = cur_left->_bf;
		RotateR(cur);
		RotateL(parent);
		//更新平衡因子
		if (CL_bf == 0)
		{
    
    
			cur->_bf = parent->_bf = cur_left->_bf = 0;
			//虽然没必要,但是起到了解耦的作用。
		}
		else if (CL_bf == 1)
		{
    
    
			parent->_bf = -1;
			cur->_bf = cur_left->_bf = 0;
		}
		else if(CL_bf == -1)
		{
    
    
			cur->_bf = 1;
			parent->_bf = cur_left->_bf = 0;
		}
		else
		{
    
    
			cout << __LINE__ << ":" << endl;
			perror("平衡因子有误");
			exit(-1);
		}
	}

2.4 Double rotation gauche et droite

  • On peut comprendre que la rotation à droite doit être traitée.

Explication : Une rotation unique ne peut pas résoudre le problème car il y a un virage. Vous devez utiliser la rotation à gauche pour transformer la polyligne en ligne droite, puis effectuer une rotation à droite.

La méthode d'analyse est la même que celle de la double rotation droite-gauche.

Commençons par un simple :

Insérer la description de l'image ici
Après avoir d'abord tourné à gauche, la polyligne devient une ligne droite, se transformant en une forme à droite, puis tournant à droite. Le facteur d'équilibre final entre cur, cur_left et parent devient 0, et finalement cur_left devient le nœud racine.

Faisons un autre résumé :
Insérer la description de l'image ici
C’est toujours pareil, mais nous en discuterons dans deux situations :

  1. L'ajout d'un nouveau nœud au c-tree fera passer le facteur d'équilibre de cur à -1 et le facteur d'équilibre du parent à 0.
  2. L'ajout d'un nouveau nœud au b-tree fera passer le facteur d'équilibre de cur à 0 et le facteur d'équilibre du parent à 1.
  3. Peu importe sur qui se trouve le nouveau nœud, le facteur d'équilibre de cur_right est de 0.

  • Résumer
  1. Le facteur d'équilibre cur_right est de 1, ce qui signifie que le nouveau nœud est sur l'arbre b, ce qui fera que le facteur d'équilibre de cur deviendra 0 et que le facteur d'équilibre du parent deviendra 1.
  2. Le facteur d'équilibre de cur_right est de -1. L'ajout d'un nouveau nœud au c-tree fera passer le facteur d'équilibre de cur à -1 et le facteur d'équilibre du parent à 0.
  3. Le facteur d'équilibre de cur_right est 0, et les facteurs d'équilibre de cur et parent deviennent tous deux 0.
  4. Peu importe sur qui se trouve le nouveau nœud, le facteur d'équilibre de cur_right est de 0.
  • Code
		void RotateLR(Node* parent)
		{
    
    
			Node* cur = parent->_left;
			Node* cur_right = cur->_right;
			int CR_bf = cur_right->_bf;

			RotateL(cur);
			RotateR(parent);

			if (CR_bf == 0)
			{
    
    
				parent->_bf = cur->_bf = cur_right->_bf = 0;
			}
			else if(CR_bf == 1)
			{
    
    
				cur->_bf = -1;
				parent->_bf = cur_right->_bf = 0;
			}
			else if (CR_bf == -1)
			{
    
    
				parent->_bf = 1;
				cur->_bf = cur_right->_bf = 0;
			}
			else
			{
    
    
				cout << __LINE__ << ":" << endl;
				perror("平衡因子有误");
				exit(-1);
			}
		} 

②Vérification

illustrer:

  1. Vérifier la différence de hauteur de chaque sous-arbre selon la définition
  2. Il est nécessaire de déterminer si la différence de hauteur du sous-arbre droit actuel est égale au facteur d'équilibre

Juger directement en fonction du facteur d'équilibre semble un peu auto-infligé. Pouvez-vous garantir que le facteur d'équilibre que vous avez mis à jour est correct ? Je ne peux même pas le garantir.

1. Trouvez la hauteur d'un arbre binaire

  • Parcours post-commande
	size_t Height(Node* root)
	{
    
    
		if (root == nullptr)
		{
    
    
			return 0;
		}

		int LHeight = Height(root->_left);
		int RHeight = Height(root->_right);


		return max(LHeight, RHeight) + 1;
	}

2. Déterminez s'il s'agit d'un arbre AVL

	bool _IsAVLTree(Node* root)
	{
    
    
		if (root == nullptr)
		{
    
    
			return true;
		}
		int RHeight = Height(root->_right);
		int LHeight = Height(root->_left);

		if (abs(RHeight - LHeight) > 1 || root->_bf != RHeight - LHeight)
		{
    
    
			return false;
		}

		return _IsAVLTree(root->_left) && _IsAVLTree(root->_right);
	}

Optimisez-le :

	bool IsAVLTree()
	{
    
    
		bool is_AVL = true;
		_IsAVLTree(_root, is_AVL);

		return is_AVL;
	}

	int _IsAVLTree(Node* root,bool& is_AVL)
	{
    
    
		if (root == nullptr)
		{
    
    
			return 0;
		}
		int RHeight = _IsAVLTree(root->_right, is_AVL);
		int LHeight = _IsAVLTree(root->_left, is_AVL);

		if (abs(RHeight - LHeight) > 1 || root->_bf != RHeight - LHeight)
		{
    
    
			is_AVL = false;
		}
		return max(RHeight, LHeight) + 1;
	}

Code source

#include<iostream>
#include<assert.h>
using namespace std;
namespace MY_STL
{
    
    
	template<class Key,class Val>
	struct  AVLTreeNode
	{
    
    
		typedef AVLTreeNode<Key, Val> Node;
		AVLTreeNode(const pair<Key,Val>& key = pair<Key,Val>())
			:_key(key.first)
			,_val(key.second)
			,_left(nullptr)
			,_right(nullptr)
			,_parent(nullptr)
			,_bf(0)
		{
    
    }

		Key _key;
		Val _val;
		//三叉链的结构
		Node* _left;
		Node* _right;
		Node* _parent;
		int _bf;
	};
	template<class Key, class Val>
	class AVLTree
	{
    
    
		typedef AVLTreeNode<Key, Val> Node;
	public:
		AVLTree()
		{
    
    }

		bool insert(const pair<Key,Val>& val)
		{
    
    
			//第一步:插入操作
			//如果根节点为空
			if (_root == nullptr)
			{
    
    
				_root = new Node(val);
				return true;
			}
			else
			{
    
    
				Node* cur = _root,*parent = _root;
				while (cur)
				{
    
    
					if (cur->_key > val.first)
					{
    
    
						parent = cur;
						cur = cur->_left;

					}
					else if(cur->_key < val.first)
					{
    
    
						parent = cur;
						cur = cur->_right;

					}
					else
					{
    
    
						return false;
					}
				}
				cur = new Node(val);
				if (parent->_key > val.first)
				{
    
    
					parent->_left = cur;
				}
				else
				{
    
    
					parent->_right = cur;
				}
				//更新新增结点的_parent
				cur->_parent = parent;

				//第二步:更新平衡因子
				//平衡因子:
				//1. 定义为右子树的高度减去左子树的高度
				//2. 合法范围为{-1,0,1}
				//3. 新增结点在左,父节点的平衡因子减1
				//4. 新增结点在右,父节点的平衡因子加1
				//5. 当父节点的平衡因子变为0——由-1变0或者1变0时,此时AVL树的高度不变
				//6. 当父节点的平衡因子变为1或者-1,AVL子树的高度变化,继续向上变化。
				//7. 当父节点的平衡因子变为2或者-2时,此时需要旋转,进行平衡
				//8. 当父节点为根节点时,此时需要结束循环。

				while (cur != _root)
				{
    
    
					//更新平衡因子
					if (parent->_left == cur)
					{
    
    
						//左减1
						(parent->_bf)--;
					}
					else
					{
    
    
						//右加1
						(parent->_bf)++;
					}
					//判断平衡因子
					if (parent->_bf == 0)
					{
    
    
						break;
					}
					else if (parent->_bf == 1 || parent->_bf == -1)
					{
    
    
						cur = parent;
						parent = cur->_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);
						//}
						if (parent->_bf == 2)
						{
    
    
							//左单旋
							if (cur->_bf == 1)
							{
    
    
								RotateL(parent);
							}
							else
							{
    
    
								RotateRL(parent);
							}
						}
						else
						{
    
    
							//右单旋
							if (cur->_bf == -1)
							{
    
    
								RotateR(parent);
							}
							else
							{
    
    
								RotateLR(parent);
							}
						}
						
						//旋转完成,树达到平衡
						break;
					}
				}
				

				return true;
			}
		}
		//根据定义进行判断
		bool IsAVLTree()
		{
    
    
			bool is_AVL = true;
			_IsAVLTree(_root, is_AVL);

			return is_AVL;

			//return _IsAVLTree(_root);
		}

		void Print()
		{
    
    
			_InOrder(_root);
			cout << endl;
		}
		//根据平衡因子进行判断
		//bool IsAVLTree()
		//{
    
    
		//	return _IsAVLTree(_root);
		//}

	private:
		void _InOrder(Node* root)
		{
    
    
			if (root == nullptr)
			{
    
    
				return;
			}
			_InOrder(root->_left);
			cout << root->_key << " ";
			_InOrder(root->_right);
		}
		//bool _IsAVLTree(Node* root)
		//{
    
    
		//	if (root == nullptr)
		//		return true;
		//	if (root->_bf >= 2 || root->_bf <= -2)
		//	{
    
    
		//		return false;
		//	}
		//	else
		//	{
    
    
		//		return _IsAVLTree(root->_left) && _IsAVLTree(root->_right);
		//	}
		//}

		//bool IsAVLTree()
		//{
    
    
		//	bool is_AVL = true;
		//	_IsAVLTree(_root, is_AVL);

		//	return is_AVL;
		//}

		size_t Height(Node* root)
		{
    
    
			if (root == nullptr)
			{
    
    
				return 0;
			}

			int LHeight = Height(root->_left);
			int RHeight = Height(root->_right);


			return max(LHeight, RHeight) + 1;
		}
		int _IsAVLTree(Node* root,bool& is_AVL)
		{
    
    
			if (root == nullptr)
			{
    
    
				return 0;
			}
			int RHeight = _IsAVLTree(root->_right, is_AVL);
			int LHeight = _IsAVLTree(root->_left, is_AVL);

			if (abs(RHeight - LHeight) > 1 || root->_bf != RHeight - LHeight)
			{
    
    
				is_AVL = false;
			}
			return max(RHeight, LHeight) + 1;
		}

		bool _IsAVLTree(Node* root)
		{
    
    
			if (root == nullptr)
			{
    
    
				return true;
			}
			int RHeight = Height(root->_right);
			int LHeight = Height(root->_left);

			if (abs(RHeight - LHeight) > 1 || root->_bf != RHeight - LHeight)
			{
    
    
				return false;
			}

			return _IsAVLTree(root->_left) && _IsAVLTree(root->_right);
		}

		void RotateLR(Node* parent)
		{
    
    
			Node* cur = parent->_left;
			Node* cur_right = cur->_right;
			int CR_bf = cur_right->_bf;

			RotateL(cur);
			RotateR(parent);

			if (CR_bf == 0)
			{
    
    
				parent->_bf = cur->_bf = cur_right->_bf = 0;
			}
			else if(CR_bf == 1)
			{
    
    
				cur->_bf = -1;
				parent->_bf = cur_right->_bf = 0;
			}
			else if (CR_bf == -1)
			{
    
    
				parent->_bf = 1;
				cur->_bf = cur_right->_bf = 0;
			}
			else
			{
    
    
				cout << __LINE__ << ":" << endl;
				perror("平衡因子有误");
				exit(-1);
			}
		}
		void RotateRL(Node* parent)
		{
    
    
			Node* cur = parent->_right;
			Node* cur_left = cur->_left;

			//CL——CurLeft
			int CL_bf = cur_left->_bf;
			RotateR(cur);
			RotateL(parent);

			if (CL_bf == 0)
			{
    
    
				cur->_bf = parent->_bf = cur_left->_bf = 0;
			}
			else if (CL_bf == 1)
			{
    
    
				parent->_bf = -1;
				cur->_bf = cur_left->_bf = 0;
			}
			else if(CL_bf == -1)
			{
    
    
				cur->_bf = 1;
				parent->_bf = cur_left->_bf = 0;
			}
			else
			{
    
    
				cout << __LINE__ << ":" << endl;
				perror("平衡因子有误");
				exit(-1);
			}
		}

		void RotateL(Node* parent)
		{
    
    
			//画图分析:
			//操作的结点有cur,cur_left,ppnode
			Node* cur = parent->_right;
			Node* cur_left = cur->_left;
			//将parent的右节点改为cur_left
			parent->_right = cur_left;
			//改变cur_left父节点的转向
			//cur_left可能为空
			if (cur_left != nullptr)
			{
    
    
				cur_left->_parent = parent;
			}
			//将parent链接在cur的左边
			//为了更新cur的parent需要保存parent的父节点
			Node* ppnode = parent->_parent;

			cur->_left = parent;
			parent->_parent = cur;

			//ppnode可能为空
			if (ppnode == nullptr)
			{
    
    
				//需要修改根节点
				_root = cur;
				cur->_parent = nullptr;
			}
			else
			{
    
    
				//改变ppnode的指向
				if (ppnode->_left == parent)
				{
    
    
					ppnode->_left = cur;
				}
				else
				{
    
    
					ppnode->_right = cur;
				}
				cur->_parent = ppnode;

			}

			//更新平衡因子
			cur->_bf = parent->_bf = 0;

		}
		void RotateR(Node* parent)
		{
    
    
			//操作的结点
			Node* cur = parent->_left;
			Node* cur_right = cur->_right;

			//第一步:将cur_right链接到parent的left
			parent->_left = cur_right;
			//更改cur_right的父节点
			//注意:cur_right可能为空
			if (cur_right != nullptr)
			{
    
    
				cur_right->_parent = parent;
			}
			//第二步:将parent链接到cur的右结点。
			//先保存一下parent的父节点
			Node* ppnode = parent->_parent;

			cur->_right = parent;
			parent->_parent = cur;
			//ppnode为空说明需要修改根节点
			if (ppnode == nullptr)
			{
    
    
				_root = cur;
				cur->_parent = nullptr;
			}
			else
			{
    
    
				if (ppnode->_left == parent)
				{
    
    
					ppnode->_left = cur;
				}
				else
				{
    
    
					ppnode->_right = cur;
				}

				cur->_parent = ppnode;
			}
			
			//更新平衡因子
			cur->_bf = parent->_bf = 0;

		}
		Node* _root = nullptr;
	};
};

Résumer

 Les arbres AVL ont également des opérations de suppression. J'en ajouterai d'autres lorsque le blogueur sera libre. De manière générale, pour les arbres AVL, il suffit de comprendre un type de rotation simple et un type de rotation double, et d'ajouter un traitement d'écriture fin. Le code Ce n'est pas difficile, mais c'est difficile. La difficulté réside dans la discussion de classement + dessin .C'est tout pour le partage d'aujourd'hui. Si vous le trouvez utile, n'hésitez pas à l'aimer et à l'encourager !

Je suppose que tu aimes

Origine blog.csdn.net/Shun_Hua/article/details/132787902
conseillé
Classement