An article teaches you what is a highly balanced binary search (AVL) tree

The concept of AVL tree

AVL tree ( Adelson-Velsky and Landis Tree ) is the earliest self-balancing binary search tree invented in computer science . In an AVL tree, the maximum height difference between two subtrees corresponding to any node is 1, so it is also called a height-balanced tree . Find, insert, and delete have average and worst-case time complexityO(logN) . Adding and removing elements may require one or more tree rotations to rebalance the tree. The AVL tree is named after its inventors, GM Adelson-Velsky and Evgenii Landis , who disclosed this data structure in their 1962 paper " An algorithm for the organization of information ."

The balancing factor of a node is the height of its left subtree minus the height of its right subtree (and sometimes the opposite). Nodes with a balance factor of 1, 0 or -1 are considered balanced. Nodes with a balance factor of -2 or 2 are considered unbalanced and require the tree to be rebalanced. The balancing factor can be stored directly in each node, or calculated from the height of a subtree that may be stored in the node.

algorithm average worst
space O(n) O(n)
search O(log n) O(log n)
insert O(log n) O(log n)
delete O(log n) O(log n)

1. Operation

The basic operations of AVL trees generally involve operating the same algorithms that operate on unbalanced binary search trees. But do one or more so-called " AVL spins " before or subsequently.

The chart below represents four situations with four columns, and each row represents the action to be performed in that situation. In the case of left-right and right-right, only one rotation operation is required; in the case of left-right and right-left, two rotation operations are required.

Please add image description

The animation below demonstrates the situation when nodes are continuously inserted into the AVL tree, and demonstrates left rotation ( Left Rotation ), right rotation ( Right Rotation ), right-left rotation ( Right-Left Rotation ), left-right rotation ( Left-Right Rotation ), and subtrees. Right Rotation with children
Insert image description here

2.Delete

Deletion from the AVL tree can be accomplished by rotating the node to be deleted downward into a leaf node, and then directly removing the leaf node. Because at most log n nodes are rotated during rotation into leaf nodes , and each AVL rotation takes a fixed time, the deletion process takes O(log n ) time overall .

3.Search

It can be performed like an ordinary binary search tree, so it takes O(log n ) time because the AVL tree is always balanced. No special preparation is required, and the structure of the tree is not changed by the search. (This is in contrast to a stretch tree search, which changes the tree structure as a result of the search.)

4. Implementation description

Assume that the balance factor is the value obtained by subtracting the height of the right subtree from the height of the left subtree. It is also assumed that the pointer of the root node of the smallest subtree that is unbalanced due to the insertion of a node in the binary sorting tree is a (that is, a is the distance from the tree). If the insertion point is the nearest ancestor node and the absolute value of the balance factor exceeds 1), the rules after losing balance can be summarized as the following four situations:

  1. One-way right-handed balancing processing LL : Since a node is inserted into the left subtree of the root node of the left subtree of *a, the balance factor of a increases from 1 to 2, causing the subtree with a as the root to lose balance, so it needs to be performed A right rotation operation;
  2. One-way left-handed balancing processing RR : Since a node is inserted into the right subtree of the root node of the right subtree of *a, the balance factor of a changes from -1 to -2, causing the subtree with a as the root to lose balance. Perform a left rotation operation;
  3. Bidirectional rotation (first left, then right) balance processing LR : Since a node is inserted into the right subtree of the root node of the left subtree of *a, the balance factor of a increases from 1 to 2, causing the subtree rooted with a to lose balance. , two rotations (first left and then right) are required.
  4. Bidirectional rotation (right first, then left) balancing processing RL : Since a node is inserted into the left subtree of the root node of the right subtree of *a, the balance factor of a changes from -1 to -2, resulting in the subtree with a as the root. If you lose your balance, you need to perform two rotations (first to the right and then to the left).

The recursive algorithm for inserting a new data element e on the balanced binary sorting tree AVL tree (Adelson-Velsky and Landis Tree) can be described as follows :

  1. If the AVL tree is an empty tree, insert a new node with the data element e as the root node of the AVL tree, and the depth of the tree increases by 1;
  2. If the key of e is equal to the key of the root node of the AVL tree, do not proceed;
  3. If the key of e is less than the key of the root node of the AVL tree, and there is no node with the same key as e in the left subtree of the AVL tree, then e is inserted into the left subtree of the AVL tree, and when When the depth of the left subtree after insertion increases (+1), the following different situations will be handled:
    1. The balance factor of the root node of the AVL tree is -1 (the depth of the right subtree is greater than the depth of the left subtree, then change the balance factor of the root node to 0, and the depth of BBST remains unchanged;
    2. The balance factor of the root node of the AVL tree is 0 (the depths of the left and right subtrees are equal): then change the balance factor of the root node to 1 and increase the depth of BBST by 1;
    3. The balance factor of the root node of the AVL tree is 1 (the depth of the left subtree is greater than the depth of the right subtree): Then if the balance factor of the root node of the left subtree of the AVL tree is 1: then one-way right-handed balancing processing is required. And after right-turn processing, the balance factor of the root node and the root node of its right subtree is changed to 0, and the depth of the tree remains unchanged;
  4. If the keyword of e is greater than the keyword of the root node of the AVL tree, and there is no node with the same keyword as e in the right subtree of the AVL tree, then e is inserted into the right subtree of the AVL tree, and when When the depth of the right subtree after insertion increases (+1), different situations are handled.

Implementation of AVL tree

1.Definition of AVL tree nodes

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)
	{
    
    }
};

This C++ template structure represents a node (AVLTreeNode) of an AVL tree. The AVL tree is a self-balancing binary search tree. This structure contains the following members:

  1. _left: Pointer to the left child node.
  2. _right: Pointer to the right child node.
  3. _parent: Pointer to parent node.
  4. _kv: A key-value pair used to store the node's keyword and associated value.
  5. _bf: Balance Factor (Balance Factor), used to represent the balance state of the node. Typically, the balancing factor is the height of the left subtree minus the height of the right subtree. AVL trees require the balance factor of each node to be in the range [-1, 1] to maintain the balance of the tree.

This structure represents a node in an AVL tree. Usually in an AVL tree implementation, you have a pointer to the root node to access the entire tree. The node structure of the AVL tree includes a balance factor _bfto help maintain the balance of the tree. When a node is inserted or deleted, corresponding rotation operations need to be performed based on the balance factor to ensure the balance of the tree.

2.Insertion of AVL tree

Here we first define the structurestruct AVLTree

Contains the following members:

typedef AVLTreeNode<K, V> Node;
private:
	Node* _root = nullptr;

Define insertion member function:

bool Insert(const pair<K, V>& kv)
{
    
    
    if (_root == nullptr)
    {
    
    
        _root = new Node(kv);
        return true;
    }

    Node* parent = nullptr;
    Node* cur = _root;
    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;

    // 控制平衡
    while (parent)
    {
    
    
        if (cur == parent->_right)
        {
    
    
            parent->_bf++;
        }
        else
        {
    
    
            parent->_bf--;
        }

        if (parent->_bf == 0)
        {
    
    
            break;
        }
        else if (abs(parent->_bf) == 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;
}

The main function of this code is to insert a new key-value pair into the AVL tree kvand maintain the balance of the tree after insertion. Here are the main steps of the code:

  1. If the tree is empty ( _root == nullptr), directly create a new root node _rootand insert it kv, then return.
  2. If the tree is not empty, enter the logic of inserting nodes:
    • Use the parentand curpointers to traverse the tree to find where the insertion should occur.
    • If curthe key of the current node is less kvthan the key of , move to the right subtree, otherwise move to the left subtree until an empty position is found to insert a new node.
  3. After inserting a new node, the node's parent node pointer needs to be updated _parent.
  4. Next is the logic to maintain the balance of the tree:
    • During the insertion process, the balance factor of the parent node is updated upwards through a loop _bf.
    • If the balance factor of a node is 0, it means that the height of its subtree has not changed , and you can stop updating the balance factor, because the balance factor of the parent node will not change either.
    • If the balance factor of a node is 1 or -1, it means that the height of its subtree has changed , and the balance factor needs to be updated upwards.
    • If the balance factor of a node is 2 or -2, it means that the tree is unbalanced and needs to be rotated to restore balance.
  5. The choice of rotation operation depends on the balancing factors of the unbalanced node and its child nodes. Generally, AVL trees have four rotation operations, namely left rotation ( RotateL ), right rotation ( RotateR ), left and right rotation ( RotateLR ) and right left rotation ( RotateRL ).

Update rules for balancing factors

  1. New additions are on the left, parent->bf--; New additions are on the right,parent->bf++
  2. After the update, parent->bf==1 or -1, it means that the balance factor of the parent before the insertion is 0, which means that the height of the left and right subtrees is equal. After the insertion, one side is higher and needs to continue to be updated.
  3. After updating, parent->bf==0, it means that the balance factor before parent is inserted is 1 or -1, which means that one side of the left and right subtrees is high and the other is low. After the insertion, both sides are the same height. The short side is filled in by the insertion. The height of the subtree where the parent is located remains unchanged, and there is no need to continue going up. renew
  4. After the update, parent->bf==2 or -2, it means that the balance factor before the parent is inserted is 1 or -1, the critical value has been balanced, and the insertion becomes 2 or -2, the subtree where the parent is located needs to be rotated.
  5. After the update, parent->bf>2 or <-2, this condition is not true. If it exists, it means that there was a problem before the insertion and needs to be checked forward.

3.Rotation of AVL tree

If a new node is inserted into an originally balanced AVL tree, it may cause imbalance. At this time, the structure of the tree must be adjusted to make it balanced. Depending on the insertion position of the node, the rotation of the AVL tree is divided into four types:

3.1 The new node is inserted to the right of the higher right subtree - right-right: left single rotation

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;

    if (_root == parent)
    {
    
    
        _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;
}
  1. First, save the pointers parentto the right subtree of parent node subRand subRthe left subtree of .subRL
  2. Point parentthe right subtree pointer of _right, subRLwhich will subRLbe used as the new parentright subtree of .
  3. If subRLexists (not nullptr), the subRLparent node pointer of _parentis pointed to parentto ensure that the tree is connected correctly.
  4. Get parentthe pointer to the parent node ppNodeof the to determine how to connect subR.
  5. Point subRthe left subtree pointer _leftof parentand point parentthe parent node pointer of to complete the left rotation._parentsubR
  6. If parentis the root node ( _root == parent), you need to update the root node _rootas subRand set subRthe parent node pointer _parentof to nullptr to ensure that the root of the tree is properly connected.
  7. Otherwise, if parentis not the root node, connect to the correct location based on the position of parentin its parent node , and update the parent node pointer of .ppNodesubRsubR_parentppNode
  8. Finally, set the balance factor of parentand to 0, since their heights are unchanged after the left rotation.subR_bf

3.2 The new node is inserted to the left side of the higher left subtree - left-left: right single rotation

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

        subL->_parent = ppNode;
    }

    subL->_bf = parent->_bf = 0;
}
  1. First, save pointers parentto the left subtree of the parent node subLand subLthe right subtree of .subLR
  2. parentPoint the left subtree pointer _leftof to , subLRwhich will subLRbe the new parentleft subtree of .
  3. If subLRexists (not nullptr), the subLRparent node pointer of _parentis pointed to parentto ensure that the tree is connected correctly.
  4. Get parentthe pointer to the parent node ppNodeof the to determine how to connect subL.
  5. Point subLthe right subtree pointer _rightof parentand point parentthe parent node pointer of to complete the right rotation._parentsubL
  6. If parentis the root node ( _root == parent), you need to update the root node _rootas subLand set subLthe parent node pointer _parentof to nullptr to ensure that the root of the tree is properly connected.
  7. Otherwise, if parentis not the root node, connect to the correct location based on the position of parentin its parent node , and update the parent node pointer of .ppNodesubLsubL_parentppNode
  8. Finally, set the balance factors of parentand to 0 since their heights do not change after right rotation.subL_bf

The principle is the same as left-handed rotation

3.3 The new node is inserted to the right side of the higher left subtree - left and right: first left single rotation and then right single rotation

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)//上图为例,新增节点在c下方
    {
    
    
        parent->_bf = 0;
        subL->_bf = -1;
    }
    else if (bf == -1)//上图为例,新增节点在b下方
    {
    
    
        parent->_bf = 1;
        subL->_bf = 0;
    }
    else if (bf == 0)//上图为例,无其他子树,60为新增节点的情况
    {
    
    
        parent->_bf = 0;
        subL->_bf = 0;
    }
    else
    {
    
    
        assert(false);
    }
}
  1. First, save pointers parentto the left subtree of the parent node subLand subLthe right subtree of , and the balance factor of .subLRsubLRbf
  2. Perform a left rotation operation parenton the left subtree subLof to adjust the structure of the subtree.
  3. Then, parentperform a right rotation operation on to make subLbecomes parentthe right subtree of .
  4. Set subLRthe balance factor _bfof to 0 because there is no change in its height after rotation.
  5. Update the node's subLRbalance factor according to different values ​​of the balance factor of :bf
    • If bfis 1, it means that subLthe height of the left subtree of is greater than the right subtree, parentset the balance factor of to 0, and subLset the balance factor of to -1.
    • If bfis -1, it means subLthat the height of the right subtree is greater than the left subtree, parentthe balance factor of is set to 1, subLand the balance factor of is set to 0.
    • If bfis 0, it means subLthat the left and right subtrees of are of equal height, and the balance factors of and are parentboth subLset to 0.
  6. If bfit is not 1, -1 or 0, it will trigger assert(false), indicating that an abnormal situation has occurred.

3.4 Insert a new node to the left side of the higher right subtree - right left: 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)
    {
    
    
        parent->_bf = 0;
        subR->_bf = 0;
    }
    else
    {
    
    
        assert(false);
    }
}
  1. First, save the pointers parentof the right subtree of the parent node subRand subRthe left subtree of , as well as the balance factor of .subRLsubRLbf
  2. Perform a right rotation operation parenton the right subtree subRof to adjust the structure of the subtree.
  3. Then, parentperform a left rotation operation on to subRbecome parentthe left subtree of .
  4. Set subRLthe balance factor _bfof to 0 because there is no change in its height after rotation.
  5. Update the node's subRLbalance factor according to different values ​​of the balance factor of :bf
    • If bfis 1, it means that subRLthe height of the left subtree of is greater than the right subtree, subRset the balance factor of to 0, and parentset the balance factor of to -1.
    • If bfis -1, it means subRLthat the height of the right subtree is greater than the left subtree, subRthe balance factor of is set to 1, parentand the balance factor of is set to 0.
    • If bfis 0, it means subRLthat the left and right subtrees of are of equal height, and the balance factors of and are parentboth subRset to 0.
  6. If bfit is not 1, -1 or 0, it will trigger assert(false), indicating that an abnormal situation has occurred.

The principle is the same as first turning left and then turning right

Summary :
If the subtree rooted at pParent is unbalanced, that is, the balance factor of pParent is 2 or -2, consider the following situations

  1. The balance factor of pParent is 2, indicating the height of the right subtree of pParent, and the root of the right subtree of pParent is pSubR

When pSubR's balance factor is 1, perform left single rotation
When pSubR's balance factor is -1, perform right-left double rotation

  1. The balance factor of pParent is -2, which means that the left subtree of pParent is high. Let the root of the left subtree of pParent be pSubL.

When the balance factor of pSubL is -1, a right single rotation is performed.
When the balance factor of pSubL is 1, a left or right double rotation is performed.

After the rotation is completed, the height of the subtree with the original pParent as the root is reduced, it is balanced, and there is no need to update it upwards.

4.Verification of AVL tree

4.1 Verify that it is a binary search tree

In-order traversal can obtain an ordered sequence, which is described as a binary search tree.

void InOrder()
{
    
    
    _InOrder(_root);
    cout << endl;
}
private:
    void _InOrder(Node* root)
    {
    
    
        if (root == nullptr)
        {
    
    
            return;
        }

        _InOrder(root->_left);
        cout << root->_kv.first << ":" << root->_kv.second << endl;
        _InOrder(root->_right);
    }
  1. First, check if the current node rootis empty (ie the tree is empty). Returns if empty, ending the recursion.
  2. Then, call the function recursively _InOrderto traverse the left subtree root->_left. This will visit the nodes in the left subtree in ascending order.
  3. Then, output the current node root's key and associated value, usually coutto the console using .
  4. Finally, the function is called recursively again _InOrderto traverse the right subtree root->_right. This will visit the nodes in the right subtree in ascending order.

4.2 Verify that it is a balanced tree

  1. The absolute value of the height difference of each node subtree does not exceed 1 (note that if there is no balance factor in the node)

  2. Whether the balance factor of the node is calculated correctly

height member functions

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

    return max(Height(root->_left), Height(root->_right)) + 1;
}
  1. First, check whether the current node rootis empty (that is, whether the tree is empty). If it is empty, height 0 is returned, indicating that the height of the empty tree is 0.
  2. If the current node rootis not empty, then the function is called recursively Heightto calculate the height of the left subtree and the height of the right subtree.
  3. Use maxthe function to compare the height of the left subtree and the right subtree, and then add 1 (the height of the current node) to get the height of the entire tree.
  4. Returns the height of the tree as the result of the function.

Balanced tree detection function

bool IsBalance()
{
    
    
    return _IsBalance(_root);
}
private:
	bool _IsBalance(Node* root)
	{
    
    
		if (root == nullptr)
		{
    
    
			return true;
		}

		int leftHT = Height(root->_left);
		int rightHT = Height(root->_right);
		int diff = rightHT - leftHT;

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

		return abs(diff) < 2
			&& _IsBalance(root->_left)
			&& _IsBalance(root->_right);
	}
  1. First, check if the current node rootis empty (ie the tree is empty). Returns if empty true, since an empty tree is balanced.
  2. If the current node rootis not empty, then first calculate the height of the left subtree and the right subtree, and store them in leftHTand respectively rightHT.
  3. Then, calculate the height difference between the left subtree and the right subtree (the height of the right subtree minus the height of the left subtree) and store it in diffthe variable.
  4. _bfCheck whether the balance factor of the current node is equal diff. If not, it means that the balance factor is abnormal, and an error message will be output and returned false.
  5. Continue to check whether the current node satisfies the balance condition of the AVL tree, that is, the absolute value of the balance factor does not exceed 1, and recursively check whether the left subtree and right subtree are also balanced (call the function) _IsBalance.
  6. If all conditions are met, returns trueindicates that the current subtree is balanced.

4.3 Verification use case

Regular scene 1

{
    
    16, 3, 7, 11, 9, 26, 18, 14, 15}

Special scene 2

{
    
    4, 2, 6, 1, 3, 5, 15, 7, 16, 14}  

Insert image description here

AVL tree implementation and verification of all codes

1.AVL code implementation

AVL.hpp

#pragma once
#include <iostream>
#include <algorithm>
#include <assert.h>
using namespace std;
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)
	{
    
    }
};

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

		Node* parent = nullptr;
		Node* cur = _root;
		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;

		while (parent)
		{
    
    
			if (cur == parent->_right)
			{
    
    
				parent->_bf++;
			}
			else
			{
    
    
				parent->_bf--;
			}

			if (parent->_bf == 0)
			{
    
    
				break;
			}
			else if (abs(parent->_bf) == 1)
			{
    
    
				parent = parent->_parent;
				cur = cur->_parent;
			}
			else if (abs(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)
				{
    
    
					RotateLR(parent);
				}
				else if (parent->_bf == 2 && cur->_bf == -1)
				{
    
    
					RotateRL(parent);
				}
				else
				{
    
    
					assert(false);
				}

				break;
			}
			else
			{
    
    
				assert(false);
			}
		}

		return true;
	}
	void InOrder()
	{
    
    
		_InOrder(_root);
		cout << endl;
	}

	bool IsBalance()
	{
    
    
		return _IsBalance(_root);
	}

private:
	int BalanceFactor(Node* node)
	{
    
    
		if (node == nullptr)
		{
    
    
			return 0;
		}
		return Height(node->_left) - Height(node->_right);
	}

	bool _IsBalance(Node* root)
	{
    
    
		if (root == nullptr)
		{
    
    
			return true;
		}

		int leftHT = Height(root->_left);
		int rightHT = Height(root->_right);
		int diff = rightHT - leftHT;

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

		return abs(diff) < 2
			&& _IsBalance(root->_left)
			&& _IsBalance(root->_right);
	}

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

		return max(Height(root->_left), Height(root->_right)) + 1;
	}

	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 (_root == parent)
		{
    
    
			_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;
	}

	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 (_root == parent)
		{
    
    
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
    
    
			if (ppNode->_left == parent)
			{
    
    
				ppNode->_left = subL;
			}
			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(parent->_left);
		RotateR(parent);

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

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

	void _InOrder(Node* root)
	{
    
    
		if (root == nullptr)
		{
    
    
			return;
		}

		_InOrder(root->_left);
		cout << root->_kv.first << ":" << root->_kv.second << endl;
		_InOrder(root->_right);
	}
private:
	Node* _root = nullptr;
};

2.AVL verification code implementation

AVLTEST.cpp

#include "AVL.hpp"
int main()
{
    
    
    //int a[]={16, 3, 7, 11, 9, 26, 18, 14, 15};
    int a[] = {
    
     4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
    AVLTree<int, int> avl1;
    for (auto e : a)
        avl1.Insert(make_pair(e, e));

    avl1.InOrder();

    cout << "IsBlance:" << avl1.IsBalance() << endl;
    return 0;
}

Guess you like

Origin blog.csdn.net/kingxzq/article/details/132779598