平衡搜索树-AVLTree的简单实现

AVL树是一种高度平衡的二叉搜索树,由Adelson-Velskii和Landis在1962年提出。其特性是左右子树高度差不超过1,平衡因子为-1、0、1。AVL树的查找、插入、删除操作在平均和最坏情况下的时间复杂度为O(log n)。文章介绍了AVL树的性质并提供了代码实现。
摘要由CSDN通过智能技术生成

1.什么是AVL树

    AVL树又称为高度平衡的二叉搜索树,它能保持二叉树的高度平衡,尽量降低二叉树的高度,减少树的平均搜索长度(近似完全二叉树)。

2.为什么叫AVL树呢?

     应该是因为它是由俄罗斯数学家G.M.Adel'son-Vel'skii和E.M.Landis在1962年提出来的,所以以他们的名字命名了平衡搜索树。^*^

3.AVL树的性质:

(1)左子树和右子树的高度之差的绝对值不超过1;

(2)树中的每个左子树、右子树都是AVL树;

(3)每个节点都有一个平衡因子(balance factor-bf),任意节点的平衡因子是-1、0、1。(每个节点的平衡因子等于右子树的高度减去左子树的高度)

4.AVL树的效率:

查找、插入和删除在平均和最坏情况下的时间复杂度都是log以2为底n的对数。

5.代码实现AVL树:

#pragma once
#include<iostream>
using namespace std;
#include<math.h>

template<class K, class V>
struct AVLTreeNode
{
	AVLTreeNode* _left;
	AVLTreeNode* _right;
	AVLTreeNode* _parent;

	K _key;
	V _value;

	int _bf; // 平衡因子 

	AVLTreeNode(const K& key,const V& value)
		:_left(NULL)
		, _right(NULL)
		, _parent(NULL)
		, _key(key)
		, _value(value)
		, _bf(0)
	{}
};

template<class K, class V>
class AVLTree
{
	typedef AVLTreeNode<K,V> Node;
public:
	AVLTree()
		:_root(NULL)
	{}
	bool Insert(const K& key, const V& value)//插入
	{
		if (_root == NULL)
		{
			_root = new Node(key, value);
			return true;
		}
		Node* parent = NULL;
		Node* cur = _root;
              //寻找插入位置
		while (cur)
		{
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}
               //在找到的位置插入
		cur = new Node(key, value);
		if (parent->_key > key)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;
               //插入后 更新平衡因子:插入一个结点后,它的父亲结点平衡因子变为0,则不继续向上更新;如果父亲结点的
             平衡因子变为1或-1,需要一直向上更新,直到父亲结点为空;如果父亲结点的平衡因子是2,就需要旋转
		if (cur == parent->_left)
			parent->_bf--;
		else
			++ parent->_bf;
		while (parent)
		{
			if (parent->_bf == 0)
			{
				return true;
			}
			else if (parent->_bf == 1 || parent->_bf == -1)
			{
				Node* gradparent = parent->_parent;
				if (gradparent)
				{
					if (parent == gradparent->_left)
						--gradparent->_bf;
					else
						++gradparent->_bf;
				}
				parent = parent->_parent;
			}
			else
			{
				if (parent->_bf == 2)
				{
					if (parent->_right->_bf == 1)
						RotateL(parent);
					else
						RotateRL(parent);
				}
				else if (parent->_bf == -2)
				{
					if (parent->_left->_bf == -1)
						RotateR(parent);
					else
						RotateLR(parent);
				}
				break;
			}	
		}
		return true;
	}

//左右单旋的时候也要调平衡因子,以下面的测试代码为例,在插入9后,需要右单旋。一开始旋转成功了,但是代码还是有误,最后
发现平衡因子出现问题,改了平衡因子就对了。同理插入26后也需要在左单旋处改平衡因子,如下图所示。
	void RotateR(Node* parent)//右单旋
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		if (subLR != NULL)
			subLR->_parent = parent;
		parent->_bf = 0;
		   
		Node* gradparent = parent->_parent;
		subL->_right = parent;
		parent->_parent = subL;
		subL->_bf = 0;
		if (gradparent == NULL)
		{
			_root = subL;
			subL->_parent = NULL;
		}
		else
		{
			if (gradparent->_left == parent)
			{
				gradparent->_left = subL;
			}
			else
			{
				gradparent->_right = subL;
			}
			subL->_parent = gradparent;
		}
	}
	void RotateL(Node* parent)//左单旋
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;
		parent->_bf = 0;

		Node* gradparent = parent->_parent;
		subR->_left = parent;
		parent->_parent = subR;
		subR->_bf = 0;
		if (gradparent == NULL)
		{
			_root = subR;
			subR->_parent = NULL;
		}
		else
		{
			if (gradparent->_left == parent)
				gradparent->_left = subR;
			else
				gradparent->_right = subR;
			subR->_parent = gradparent;
		}
	}
	void RotateLR(Node* parent)//先左后右双旋
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		int bf = subLR->_bf;

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

		if (bf == -1)
		{
			subL->_bf = 0;
			parent->_bf = 1;
			subLR->_bf = 0;
		}
		else if (bf == 1)
		{
			subL->_bf = -1;
			parent->_bf = 0;
			subLR->_bf = 0;
		}
		else
			subL->_bf = parent->_bf = 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)
		{
			subR->_bf = 1;
			parent->_bf = 0;
			subRL->_bf = 0;
		}
		else if (bf == 1)
		{
			subR->_bf = 0;
			parent->_bf = -1;
			subRL->_bf = 0;
		}
		else
		{
			subR->_bf = parent->_bf = subRL->_bf = 0;
		}
	}
		void InOrder()
		{
			cout << "InOrder" << endl;
			_InOrder(_root);
			cout << endl;
		}

		bool IsBalance()
		{
			return _IsBalance(_root);
		}
protected:
	void _InOrder(Node* root)
	{
		if (root == NULL)
		{
			return;
		}
		else
		{
			_InOrder(root->_left);
			cout << root->_key << " ";
			_InOrder(root->_right);
		}
	}

	//bool _IsBalance(Node* root,size_t height)//时间复杂度是O(n)
	//{
	//	if (root == NULL)
	//	{
	//		height = 0;
	//		return true;
	//	}

	//	int LeftHeight = 0;
	//	int RightHeight = 0;
	//	if(_IsBalance(root->_left, LeftHeight) == false)
	//		return false;
	//	if(_IsBalance(root->_right, RightHeight) == false)
	//		return false;

	//	height = LeftHeight > RightHeight ? LeftHeight + 1 : RightHeight + 1;
	//	return (abs(RightHeight - LeftHeight)) < 2;

	//}

	bool _IsBalance(Node* root)//判断是否平衡
	{
		if (root == NULL)
		{
			return true;
		}
		int LeftHeight = Height(root->_left);
		int RightHeight = Height(root->_right);

		return (abs(LeftHeight - RightHeight) < 2)
			&& _IsBalance(root->_left)
			&& _IsBalance(root->_right);
	}
	int Height(Node* root)
	{
		if (root == NULL)
			return 0;

		int l = Height(root->_left);
		int r = Height(root->_right);
		return l > r ? l + 1 : r + 1;
	}

private:
	Node* _root;
};


测试代码:
void TestAVLTree()
{
	int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
	AVLTree<int, int> t;
	//for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
	//{
	//	t.Insert(a[i], a[i]);
	//}
	t.Insert(16,0);
	t.Insert(3,0);
	t.Insert(7,0);
	t.Insert(11, 0);
	t.Insert(9, 0);
	t.Insert(26, 0);
	t.Insert(14, 0);
	t.Insert(18, 0);//这种插入方式方便查找错误,对于我这种菜鸟^o^

	cout << t.IsBalance() << endl;
	t.InOrder();
}



注意:写代码时注意分清逻辑等于和赋值等于。

 一图以16为父亲节点右单旋变二图,更新parent、subL的平衡因子_bf;三图以7为父亲节点左单旋变四图,也需要更新parent、subR的平衡因子_bf。


左右双旋,因为不确定子树的情况,可能为空,有一个结点,再或者连着高度为h的子树,因此不光要旋转还要更新平衡因子,可以根据图思考代码;右左双旋同理。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值