AVLTree(二叉平衡树)——数据结构

平衡二叉树

如果二叉搜索树的插入序列是有序的或者是接近有序,那么二叉搜索树就会退化为单支数(类似单链表),查找元素相当于在顺序表中搜索元素,效率低下。

AVLtree(Adelson Velskii Landis tree)是一个加上额外平衡条件的二叉搜索树,左右子树高度之差(简称平衡因子)的绝对值不超过1,如果它有n个节点,高度可保持在O(logn),搜索时间复杂度为O(logn)。

AVL树的节点

template<class K, class V>
struct AVLTreeNode
{
	AVLTreeNode<K, V>* _left;//左子节点
	AVLTreeNode<K, V>* _right;//右子节点
	AVLTreeNode<K, V>* _parent;//
	int _bf; // 平衡因子,不是必须,我们这里选择用它来实现
	pair<K, V> _kv;

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

插入

  1. 先按照二叉搜索树的规则将节点插入到AVL树中
  2. 节点插入之后,对平衡因子进行更新
    1. 如果插入到左侧,只需要将平衡因子-1
    2. 如果插入到右侧,只需要将平衡因子+1
  3. 此时平衡因子有三种情况
    1. 平衡因子为0,插入之前平衡因子为正负1,插入后被调整为0,此时满足AVL树的性质,插入成功
    2. 平衡因子为正负1,插入之前平衡因子为0,插入之后需要继续向上更新
    3. 平衡因子为正负2,则违反了AVL树的性质,需要对其进行旋转处理

旋转处理

  1. 左单旋
    在这里插入图片描述

    void RotateL(Node* parent)
    {
        Node* subR=parent->_right;
        Node* subRL=subR->_left;
        
        parent->_right=subRL;
        //subRL则不用重新设置父节点
        if(subRL)
            subRL->_parent=parent;
        
        subRL->_left=parent;
        Node* ppNode=parent->_parent;
        parent->_parent=subR;
        
        //判断parent是不是根节点
        if(parent==_root)
        {
            _root=subR;
            subR->_parent=nullptr;
        }
        else 
        {
            if(ppNode->_left==parent)
                ppNode->_left=subR;
            else
                ppNode->_right=sunR;
            subR->_parent=ppNode;
        }
        subR->bf=parent->_bf=0;
    }
    
  2. 右单选
    在这里插入图片描述

    void RotateR(Node* parent)
    {
        Node* subL=parent->_left;
        Node* subLR=subL->_right;
        
        parent->_left=subLR;
        if(subLR)
        	subLR->_parent=parent;
        
        subL->_right=parent;
        Node* parent=parent->_parent;
        parent->_parent=subL;
        
        if(parent==_root)
        {
            _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;
    }
    
  3. 左右双旋
    在这里插入图片描述

    void RetateLR(Node* parent)
    {
        Node* subL=parent->_left;
        Node* subLR=subL->_right;
        int bf=subLR->_bf;
        RotateL(parent->_left);
        RotateR(parent);
        
        if(bf==1)
        {
            parent->_bf=0;
            subL->_bf=1;
            subLR->_bf=0;
        }
        else if(bf==-1)
        {
            parent->_bf=-1;
            subR->_bf=0;
            subLR->_bf=0;
        }
        else if(bf==0)
        {
            parent->_bf=0;
            subR->_bf=0;
            subLR->_bf=0;
        }
    }
    
  4. 右左双旋
    在这里插入图片描述

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

插入的实现

bool Insert(const pair<K,V>& kv)
{
    //1、按照二叉搜索树的规则进行插入
    if(_root==nullptr)
    {
        _root=new Node(kv);
        _root->_bf=0;
        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;
        cur->_parent=parent;
    }
    else
    {
        parent->_left=cur;
        cur->_parent=parent;
    }
    
    //2、更新平衡因子
    while(parent)
    {
        if(cur==parent->_right)
            parent->_bf--;
        else
            parent->_bf++;
        
        if(parent->_bf==0)
        {
            break;
        }
        else if(abs(parent->_bf)==1)
        {
            cur=parent;
            parent=parent->_parent;
        }
        else if(abs(parent->_bf)==2)
        {
            //需要旋转来处理,来让二叉树平衡
            if(parent->_bf==2)
            {
                if(cur->_bf==1)
                    RotateR(parent);
                else if(cur->_bf==-1)
                    RotateLR(parent);
            }
            else if(parent->_bf==-2)
            {
                if(cur->_bf==-1)
                    RotateL(parent);
                else if(cur->_bf==1)
                    RotateRL(parent);
            }
            break;
        }
        else
        {
            assert(false);
        }
    }
    return true;
}

模拟实现

#pragma once
#include <iostream>
#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;
	int _bf; // balance factor  // 不是必须,我们这里选择用它来实现
	pair<K, V> _kv;

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

template<class K, class V>
class AVLTree
{
	typedef AVLTreeNode<const K, V> Node;
public:
	AVLTree() = default;

	// t2(t1)
	AVLTree(const AVLTree<K, V>& t)
		:_root(nullptr)
	{
		_root = _Copy(t._root);
	}

	Node* _Copy(Node* root)
	{
		if (root == nullptr)
			return nullptr;
		Node* newroot = new Node(root->_kv);
		newroot->_bf = root->_bf;
		newroot->_left = _Copy(root->_left);
		newroot->_right = _Copy(root->_right);

		return root;
	}

	~AVLTree()
	{
		_Destory(_root);
		_root = nullptr;
	}

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

		_Destory(root->_left);
		_Destory(root->_right);

		delete root;
	}

	bool Insert(const pair<K, V>& kv)
	{
		// 1.按搜索的规则将插入值
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_bf = 0;
			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;
			cur->_parent = parent;
		}
		else
		{
			parent->_left = cur;
			cur->_parent = parent;
		}

		// 1.更新平衡因子
		while (parent)
		{
			if (cur == parent->_right)
				parent->_bf--;
			else if (cur == parent->_left)
				parent->_bf++;

			if (parent->_bf == 0)
			{
				break;
			}
			else if (abs(parent->_bf) == 1)
			{
				cur = parent;
				parent = parent->_parent;
			}
			else if (abs(parent->_bf) == 2)
			{
				// 说明parent子树已经不平衡,需要旋转处理,让他平衡
				if (parent->_bf == 2)
				{
					if (cur->_bf == 1)
					{
						RotateR(parent);
					}
					else if (cur->_bf == -1)
					{
						RotateLR(parent);
					}
				}
				else if (parent->_bf == -2)
				{
					if (cur->_bf == -1)
					{
						RotateL(parent);
					}
					else if (cur->_bf == 1)
					{
						RotateRL(parent);
					}
				}

				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;

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

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

	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;

		subL->_right = parent;
		Node* ppNode = parent->_parent;
		parent->_parent = subL;

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

	void RotateLR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		int bf = subLR->_bf;
		RotateL(parent->_left);
		RotateR(parent);

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

	void RotateRL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		int bf = subRL->_bf;

		RotateR(parent->_right);
		RotateL(parent);

		if (bf == -1)
		{
			parent->_bf = 1;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else if (bf == 1)
		{
			parent->_bf = 0;
			subR->_bf = -1;
			subRL->_bf = 0;
		}
		else if (bf == 0)
		{
			parent->_bf = 0;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
	}

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

		_InOrder(root->_left);
		cout << root->_kv.first << " ";
		_InOrder(root->_right);
	}

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

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

		int leftDepth = _Depth(root->_left);
		int rightDepth = _Depth(root->_right);

		return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
	}

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

		int leftDepth = _Depth(root->_left);
		int rightDepth = _Depth(root->_right);

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

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

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

	Node* Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_kv.first < key)
				cur = cur->_right;
			else if (cur->_kv.first > key)
				cur = cur->_left;
			else
				return cur;
		}

		return NULL;
	}

private:
	Node* _root = nullptr;
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值