[C++] AVL tree (height balanced binary tree)

concept

Although the binary search tree can shorten the search efficiency, if the data is ordered or close to ordered, the binary search tree will degenerate into a single branch tree. Searching for elements is equivalent to searching for elements in a sequence table, which is inefficient.
. Therefore, two Russian mathematicians GMAdelson-Velskii and EMLandis invented a method to solve the above problem in 1962: after inserting a new node into the binary search tree, if the left and right subtrees of each node can be guaranteed If the absolute value of the height difference does not exceed 1 (nodes in the tree need to be adjusted), the height of the tree can be reduced, thereby reducing the average search length.

Characteristics of an AVL tree:
Its left and right subtrees are both AVL trees.
The absolute value of the height difference between the left and right subtrees (referred to as the balance factor) does not exceed 1 (-1/0/1).
If a binary search tree is highly balanced , it is the AVL tree. If it has n nodes, its height can be maintained at
O ​​(log 2 n) O(log_2 n)O(log2n ) , search time complexity O(log 2 n log_2 nlog2n)。

Insert image description here

AVL tree node definition

template<class K,class V>
struct AVLTreeNode
{
    
    
	AVLTreeNode<K, V>* _left;// 该节点的左孩子
	AVLTreeNode<K, V>* _right;// 该节点的右孩子
	AVLTreeNode<K, V>* _parent;// 该节点的父节点

	pair<K, V> _kv;// 该节点的平衡因子
	int _bf;

	AVLTreeNode(const pair<K,V>& kv)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_kv(kv)
		,_bf(0)
	{
    
    }
};

AVL tree node insertion

The AVL tree introduces a balance factor based on the binary search tree, so the AVL tree can also be regarded as a binary search tree. Then
the insertion process of AVL tree can be divided into two steps:
1. Insert new nodes according to the binary search tree
2. Adjust the balance factor of the node

Insert image description here

Rules for updating balance factors:
1. New additions are on the right, parent->bf++; New additions are on the left, parent->bf–:
2. After updating, parent->bf == 1 r -1, indicating that parent is inserted before The balance factor is 0, which means that the heights of the left and right subtrees are equal. After the insertion, one side is higher. The height of the parent has changed, and you need to continue to update. 3. After the update, parent-
>bf == 0, which means that the balance factor before the parent was inserted was 1. r -1, indicating that one side of the left and right subtrees is high and the other side is low. After the insertion, both sides are the same height. The insertion fills in the shorter side. The height of the subtree where the parent is located remains unchanged. There is no need to continue to update. 4 After the update, parent-
> bf == 2 r -2, indicating that the balance factor before the parent is inserted is 1 or -1, which has balanced the critical value. The insertion becomes 2 or -2, breaking the balance, and the subtree where the parent is located needs to be rotated.
5After the update, the value of parent->bf > 2 r< -2 is impossible. If it exists, it means that it was not an AVL tree before the insertion, and you need to check the problem of the previous operation.

Four rotation situations of AVL tree

left unirotation

Insert image description here

	void RotateL(Node* parent)
	{
    
    
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		parent->_right = subRL;
		if (subRL)
		{
    
    
			subRL->_parent = parent;
		}

		Node* ppNode = parent->_parent;
		subR->_left = parent;
		parent->_parent = subR;

		//1.parent是整棵树的根
		//2.parent是子树的根
		if (parent == _root)
		{
    
    
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
    
    
			if (ppNode->_left == parent)
			{
    
    
				ppNode->_left = subR;
			}
			else
			{
    
    
				ppNode->_right = subR;
			}
			subR->_parent = ppNode;
		}
		subR->_bf = parent->_bf = 0;
	}
right unirotation

Insert image description here

	//右单旋
	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 (ppNode == nullptr)
		{
    
    
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
    
    
			if (ppNode->_left == parent)
			{
    
    
				ppNode->_left = subL;
			}
			else
			{
    
    
				ppNode->_right = subL;
			}
			subL->_parent = ppNode;
		}

		parent->_bf = subL->_bf = 0;
	}
First spin left and then spin right

Insert image description here

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)
		{
    
    
 			subL->_bf = -1;
		}
		else if (bf == -1)
		{
    
    
			parent->_bf = 0;
			subL->_bf = 1;
		}
		else if (bf == 0)
		{
    
    
			parent->_bf = 0;
			subL->_bf = 0;
		}
		else
		{
    
    
			assert(false);
		}
	}
First rotate right and then rotate left

Insert image description here

	//右左双旋
	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)
		{
    
    
			subR->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
    
    
			assert(false);
		}
	}

Inserting elements and controlling balance

typedef AVLTreeNode<K, V> Node;
	bool Insert(const pair<K, V>& kv)
	{
    
    
		//如果当前树为空直接设置节点
		if (_root == NULL)
		{
    
    
			_root = new Node(kv);
			return true;
		}
		//需要有指针记录上一个移动位置
		Node* cur = _root;
		Node* parent = nullptr;
		//寻找合适位置插入
		while (cur)
		{
    
    
			if (cur->_kv.first < kv.first)
			{
    
    
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > kv.first)
			{
    
    
				parent = cur;
				cur = cur->_left;
			}
			else
			{
    
    
				return false;
			}
		}
		//直接插入节点并设置它的指向
		cur = new Node(kv);
		if (parent->_kv.first < kv.first)
		{
    
    
			parent->_right = cur;
		}
		else
		{
    
    
			parent->_left = cur;
		}
		cur->_parent = parent;
		//控制平衡
		//1.更新平衡因子
		while (parent)
		{
    
    
			if (parent->_right == cur)
			{
    
    
				parent->_bf++;
			}
			else
			{
    
    
				parent->_bf--;
			}

			if (parent->_bf == 0)
			{
    
    
				break;
			}
			else if (abs(parent->_bf) == 1)
			{
    
    	//如果为1整体向上移动再次调增平衡
				parent = parent->_parent;
				cur = cur->_parent;
			}
			else if (abs(parent->_bf) == 2)
			{
    
    
				//说明parent所在子树已经不平衡了,需要旋转处理
				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)
				{
    
    
					RotateLR(parent);
				}
				else if (parent->_bf == 2 && cur->_bf == -1)
				{
    
    
					RotateRL(parent);
				}
				else
				{
    
    
					//预防调整出错情况
					assert(false);
				}
				break;
			}
			else
			{
    
    
			//预防调整出错情况
				assert(false);
			}
		}
		return true;

	}

Determine whether the last node is balanced

	//判断是否平衡
bool _IsBanlance(Node* root)
	{
    
    
		if (root == NULL)
		{
    
    
			return true;
		}

		int leftH = _Height(root->_left);
		int rightH = _Height(root->_right);

		if (rightH - leftH != root->_bf)
		{
    
    
			cout << root->_kv.first << "节点平衡因子异常" << endl;
			return false;
		}

		return abs(leftH - rightH) < 2
			&& _IsBanlance(root->_left)
			&& _IsBanlance(root->_right);
	}

	//计算它的最大高度
	int _Height(Node* root)
	{
    
    
		if (root == nullptr)
		{
    
    
			return 0;
		}

		int leftH = _Height(root->_left);
		int rightH = _Height(root->_right);

		return max(leftH, rightH) + 1;
	}

Guess you like

Origin blog.csdn.net/wh9109/article/details/132197518