Principle and Realization of C++ AVL Tree

Today we are studying the "big brother" of the binary search tree, they are: AVL tree

The concept of AVL tree:

The full name of the AVL tree is a binary balanced search tree, which converts an unbalanced binary search tree into a balanced binary search tree by means of rotation . First, let's define the nodes of the AVL tree with code:

template <class K,class V>
struct AVLTreeNode
{
	pair<K, V> _kv;
	AVLTreeNode<K, V>* _parent;
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	int _bf;
	AVLTreeNode(const pair<K, V>& kv)
		: _kv(kv)
		, _parent(nullptr)
		, _left(nullptr)
		, _right(nullptr)
		, _bf(0)
	{

	}
};

After the node is defined, we implement the insertion function. The characteristics of the AVL tree are the same as those of the binary balanced tree. When a node is smaller than the node, it is inserted to the left, and when it is larger than the node, it is inserted to the right. If it is the same size as the data in the node, it will not be inserted:

template <class K,class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
	bool insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}

		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (kv.first > cur->_kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kv.first < cur->_kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}
		//插入数据
		cur = new Node(kv);
		// 得判断cur插入它父亲的左边还是右边
		if (parent->_kv.first > cur->_kv.first)
		{
			parent->_left = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
private:
	Node* _root = nullptr;
};

Next, we need to adjust the balance factor. When adjusting the balance factor, we need to analyze various situations of the binary tree.

Rotation of a binary tree:

In simple terms, rotation is divided into four situations, namely: left single rotation , right single rotation , left and right single rotation , and right left single rotation .

Each case corresponds to a different balance factor.

Left monorotation:

Because there are many cases of node insertion, we can use an abstract graph to represent n cases:

 Therefore, in the case of left single rotation, the balance factor of the parent is 2, and the balance factor of the right child is 1. Its code implementation is as follows:

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;

			if (ppNode == nullptr)
			{
				_root = subR;
				_root->_parent = nullptr;
			}
			else
			{
				if (ppNode->_right == parent)
				{
					ppNode->_right = subR;
					subR->_parent = ppNode;
				}
				else
				{
					ppNode->_left = subR;
					subR->_parent = ppNode;
				}
			}
			//调整bf的值
			subR->_bf = parent->_bf = 0;
		}

Right spin:

 Its implementation is similar to that of the left single rotation. The balance factor of the parent is -2, and the balance factor of the right child is -1. The code is implemented as follows:

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;
				_root->_parent = nullptr;
			}
			else
			{
				if (ppNode->_left == parent)
				{
					ppNode->_left = subL;
					subL->_parent = ppNode;
				}
				else
				{
					ppNode->_right = subL;
					subL->_parent = ppNode;
				}
			}
			//更新平衡因子
			subL->_bf = parent->_bf = 0;
		}

Summary: It is necessary to define a ppNode, the purpose is to turn the unbalanced part into a balanced part and connect it to the above node (balanced). The above node may or may not be empty, so it should be discussed according to the situation. Finally, adjust the balance factor of the node.

Left and right single rotation:

The actual situation of left single rotation and right single rotation is left slash and right slant (both straight). The left and right radios are polylines protruding to the left .

The left and right single rotation is realized by a left single rotation and then a right single rotation. However, the balance factors of these three nodes need to be discussed on a case-by-case basis. Because the situation is different when a node is inserted under b or under c, we need to define a bf, and adjust the balance factor through the value of bf. The variable code is implemented as follows:

void RotateLR(Node* parent)
		{
			Node* subL = parent->_left;
			Node* subLR = subL->_right;
			int bf = subLR->_bf;
			RotateL(subL);
			RotateR(parent);
			
			if (bf ==-1)
			{
				subL->_bf = 0;
				subLR->_bf = 0;
				parent->_bf = 1;
			 }
			else if (bf == 1)
			{
				subL->_bf = -1;
				subLR->_bf = 0;
				parent->_bf = 0;
			}
			else if (bf == 0)
			{
				subL->_bf = 0;
				subLR->_bf = 0;
				parent->_bf = 0;
			}
			else
			{
				assert(false);
			}
		}

Right left single rotation:

Right and left single rotation is similar to left and right single rotation, that is, right single rotation is performed first and then left single rotation. The code is implemented as follows:

void RotateRL(Node* parent)
		{
			Node* subR = parent->_right;
			Node* subRL = subR->_left;
			int bf = subRL->_bf;
			RotateR(subR);
			RotateL(parent);
			
			if (bf == -1)
			{
				subR->_bf = 1;
				subRL->_bf = 0;
				parent->_bf = 0;
			}
			else if (bf == 1)
			{
				subR->_bf = 0;
				subRL->_bf = 0;
				parent->_bf = -1;
			}
			else if (bf == 0)
			{
				subR->_bf = 0;
				subRL->_bf = 0;
				parent->_bf = 0;
			}
			else
			{
				assert(false);
			}
		}

The overall code of the AVL tree:

After all four rotations are figured out, the entire AVL tree can be realized:

template <class K,class V>
struct AVLTreeNode
{
	pair<K, V> _kv;
	AVLTreeNode<K, V>* _parent;
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	int _bf;
	AVLTreeNode(const pair<K, V>& kv)
		: _kv(kv)
		, _parent(nullptr)
		, _left(nullptr)
		, _right(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)
		{
			_root = new Node(kv);
			return true;
		}

		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (kv.first > cur->_kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kv.first < cur->_kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}
		//插入数据
		cur = new Node(kv);
		// 得判断cur插入它父亲的左边还是右边
		if (parent->_kv.first > cur->_kv.first)
		{
			parent->_left = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_right = 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);
				}
				break;
			}
			else
			{
				assert(false);
			}


		}
		return true;
	}
	

		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;

			if (ppNode == nullptr)
			{
				_root = subR;
				_root->_parent = nullptr;
			}
			else
			{
				if (ppNode->_right == parent)
				{
					ppNode->_right = subR;
					subR->_parent = ppNode;
				}
				else
				{
					ppNode->_left = subR;
					subR->_parent = ppNode;
				}
			}
			//调整bf的值
			subR->_bf = parent->_bf = 0;
		}

		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;
				_root->_parent = nullptr;
			}
			else
			{
				if (ppNode->_left == parent)
				{
					ppNode->_left = subL;
					subL->_parent = ppNode;
				}
				else
				{
					ppNode->_right = subL;
					subL->_parent = ppNode;
				}
			}
			//更新平衡因子
			subL->_bf = parent->_bf = 0;
		}

		void RotateLR(Node* parent)
		{
			Node* subL = parent->_left;
			Node* subLR = subL->_right;
			int bf = subLR->_bf;
			RotateL(subL);
			RotateR(parent);
			
			if (bf ==-1)
			{
				subL->_bf = 0;
				subLR->_bf = 0;
				parent->_bf = 1;
			 }
			else if (bf == 1)
			{
				subL->_bf = -1;
				subLR->_bf = 0;
				parent->_bf = 0;
			}
			else if (bf == 0)
			{
				subL->_bf = 0;
				subLR->_bf = 0;
				parent->_bf = 0;
			}
			else
			{
				assert(false);
			}
		}

		void RotateRL(Node* parent)
		{
			Node* subR = parent->_right;
			Node* subRL = subR->_left;
			int bf = subRL->_bf;
			RotateR(subR);
			RotateL(parent);
			
			if (bf == -1)
			{
				subR->_bf = 1;
				subRL->_bf = 0;
				parent->_bf = 0;
			}
			else if (bf == 1)
			{
				subR->_bf = 0;
				subRL->_bf = 0;
				parent->_bf = -1;
			}
			else if (bf == 0)
			{
				subR->_bf = 0;
				subRL->_bf = 0;
				parent->_bf = 0;
			}
			else
			{
				assert(false);
			}
		}

		
	

	
private:
	Node* _root = nullptr; 

};

Check of AVL tree balance:

The most critical thing to test the AVL tree is whether the absolute value of the difference between the left subtree and the right subtree is less than or equal to 1. We can first implement a Height function to recursively find the height of a tree:

int Height(Node* root)
		{
			if (root == nullptr)
			{
				return 0;
			}
			int left = Height(root->_left);
			int right = Height(root->_right);
			return (left > right) ? left + 1 : right + 1;
		}

Then, through a recursive function, the height difference between the left and right subtrees of each subtree is calculated to judge the balance:

bool IsBalance()
		{
			return _IsBalance(_root);
		}
		bool _IsBalance(Node* root)
		{
			if (root == nullptr)
			{
				return true;
			}
			int lheight = Height(root->_left);
			int rheight = Height(root->_right);
			if (rheight - lheight != root->_bf)
			{
				cout << "平衡因子异常:" <<root->_kv.first<< endl;
				return false;
			}
			return abs(lheight - rheight) < 2 && _IsBalance(root->_left) && _IsBalance(root->_right);
		}

The implementation of the AVL tree is all over here, thank you for reading and supporting! !

Guess you like

Origin blog.csdn.net/m0_69005269/article/details/130213017