3.3左单旋

左单旋和右单旋类似。

void RoRateL( node* parent)//左单旋
{
	node* subR = parent->right;
	node* subRL = subR->left;
	node* pparnet = parent->parent;
	parent->right = subRL;
	if (subRL)//防止subRL为空
	{
		subRL->parent = parent;//修改父节点
	}
	subR->left = parent;
	parent->parent = subR;
	if (pparnet==nullptr)//parent就是根节点
	{
		_root = subR;
		subR->parent = nullptr;
	}
	else
	{
		if (pparnet->left == parent)//确定parent节点是左还是右
		{
			pparnet->left = subR;
		}
		else 
		{
			pparnet->right = subR;
		}
		subR->parent = pparnet;//修改父节点
	}
	subR->bf = parent->bf = 0;//更新平衡因子
}
		
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">

3.4左右双旋

左右双旋的就是先左单旋再右单旋。
同时注意平衡因子的更新即可。


更新条件:parent->bf == -2 && cur->bf == 1

void RoRateLR( node* parent)//左右双旋
{
	node* subL = parent->left;
	node* subLR = subL->right;
	int bf = subLR->bf;//先记录插入后的平衡因子
	RoRateL(subL);
	RoRateR(parent);
	if (bf == 0)//分情况讨论
	{
		parent->bf = 0;
		subL->bf = 0;
		subLR->bf = 0;
	}
	else 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
	{
		assert(false);
	}
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

3.5右左双旋

右左双旋情况和左右双旋类似,这里就不过多赘述了。

更新条件:parent->bf == 2 && cur->bf == -1

3.6AVL树的插入

结合前面的知识我们就可以写出二叉搜索树的插入了。

void RoRateR( node* parent)//右单旋
{
	node* subL = parent->left;
	node* subLR = subL->right;
	node* pparnet = parent->parent;
	parent->left = subLR;
	if (subLR)
	{
		subLR->parent = parent;//修改父节点
	}
	subL->right = parent;
	parent->parent = subL;
	if (pparnet == nullptr)//parent就是根节点
	{
		_root = subL;
		subL->parent = nullptr;
	}
	else
	{
		if (pparnet->left == parent)//确定parent节点是左还是右
		{
			pparnet->left = subL;
		}
		else 
		{
			pparnet->right = subL;
		}
		subL->parent = pparnet;//修改父节点
	}
	subL->bf = parent->bf = 0;//更新平衡因子
}
void RoRateL( node* parent)//左单旋
{
	node* subR = parent->right;
	node* subRL = subR->left;
	node* pparnet = parent->parent;
	parent->right = subRL;
	if (subRL)//防止subRL为空
	{
		subRL->parent = parent;//修改父节点
	}
	subR->left = parent;
	parent->parent = subR;
	if (pparnet==nullptr)//parent就是根节点
	{
		_root = subR;
		subR->parent = nullptr;
	}
	else
	{
		if (pparnet->left == parent)//确定parent节点是左还是右
		{
			pparnet->left = subR;
		}
		else 
		{
			pparnet->right = subR;
		}
		subR->parent = pparnet;//修改父节点
	}
	subR->bf = parent->bf = 0;//更新平衡因子
}
void RoRateLR( node* parent)//左右双旋
{
	node* subL = parent->left;
	node* subLR = subL->right;
	int bf = subLR->bf;//先记录插入后的平衡因子
	RoRateL(subL);
	RoRateR(parent);
	if (bf == 0)//分情况讨论
	{
		parent->bf = 0;
		subL->bf = 0;
		subLR->bf = 0;
	}
	else 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
	{
		assert(false);
	}
}
void RoRateRL( node* parent)//右左双旋
{
	node* subR = parent->right;
	node* subRL = subR->left;
	int bf = subRL->bf;//先记录插入后的平衡因子
	RoRateR(subR);
	RoRateL(parent);
	if (bf == 0)//分情况讨论
	{
		parent->bf = 0;
		subR->bf = 0;
		subRL->bf = 0;
	}
	else 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
	{
		assert(false);
	}
}
bool Insert(const k& x, const v& v)
{
	if (_root == nullptr)//插入根节点
	{
		_root = new node(x, v);
		return true;
	}
	node* cur = _root;
	node* parent = nullptr;//保留父亲节点
	while (cur)
	{
		/*介质不冗余*/
		if (x < cur->_key)
		{
			parent = cur;
			cur = cur->left;
		}
		else if (x > cur->_key)
		{
			parent = cur;
			cur = cur->right;
		}
		else
		{
			return false;
		}
		//介质冗余
		//if (x <= cur->_key)//相等插入到左子树
		//{
		//	parent = cur;
		//	cur = cur->left;
		//}
		//else if (x > cur->_key)
		//{
		//	parent = cur;
		//	cur = cur->right;
		//}
	}
	cur = new node(x, v);
	if (x > parent->_key)
	{
		parent->right = cur;
	}
	else//相等插入左子树
	{
		parent->left = 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)
			{
				RoRateR(parent);
			}
			else if (parent->bf == 2 && cur->bf == 1)
			{
				RoRateL(parent);
			}
			else if (parent->bf == -2 && cur->bf == 1)
			{
				RoRateLR(parent);
			}
			else if (parent->bf == 2 && cur->bf == -1)
			{
				RoRateRL(parent);
			}
			else
			{
				assert(false);
			}

			break;
		}
		else
		{
			assert(false);
		}
	}
	return true;
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

3.7AVL树的查找

在避免了二叉搜索树退化为单叉树的情况。
AVL树的查找效率为O(logN).

四.AVL树的检测

4.1AVL树检测

AVL树我们可以递归检测每颗子树的左右高度差是否不差过1即可。

void Inorder()
{
	_Inorder(_root);
	cout << endl;
}
bool IsBalanceTree()
{
	return _IsBalanceTree(_root);
}
bool _IsBalanceTree(const node* root)
{
	// 空树也是AVL树
	if (nullptr == root)
		return true;
	// 计算pRoot结点的平衡因⼦:即pRoot左右⼦树的⾼度差
	int leftHeight = _Height(root->left);
	int rightHeight = _Height(root->right);
	int diff = rightHeight - leftHeight;
	// 如果计算出的平衡因⼦与pRoot的平衡因⼦不相等,或者
    // pRoot平衡因子的绝对值超过1,则⼀定不是AVL树
	if (abs(diff) >= 2)
	{
		cout << root->_value << "高度差异常" << endl;
		return false;
	}
	if (root->bf != diff)
	{
		cout << root->_key << "平衡因子异常" << endl;
		return false;
	}
	// pRoot的左和右如果都是AVL树,则该树⼀定是AVL树
	return _IsBalanceTree(root->left) && _IsBalanceTree(root->right);
}
void _Inorder(const node* root)
{
	if (root == nullptr)
	{
		return;
	}
	_Inorder(root->left);
	cout << root->_key << ":" << root->_value<<endl;
	_Inorder(root->right);
}
size_t Size()
{
	return _Size(_root);
}
size_t _Size(const node* parent)
{
	if (parent)
	{
		return 1 + _Size(parent->left)+ _Size(parent->right);
	}
	else
	{
		return 0;
	}
}
size_t Height()
{
	return _Height(_root);
}
size_t _Height(const node* parent)
{
	if (parent)
	{
		return 1 + max(_Height(parent->left), _Height(parent->right));
	}
	else
	{
		return 0;
	}
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

4.2 AVL树的验证

void TestAVLTree1()
{
	AVL::AVLTree<int, int>t;
	// 常规的测试⽤例
	//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
	// 特殊的带有双旋场景的测试⽤例
	int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
	for (auto e : a)
	{
		t.Insert(e, e);
	}
	t.Inorder();
	cout << t.IsBalanceTree() << endl;
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

在这里插入图片描述
在这里插入图片描述

void TestAVLTree2()
{
	const int N = 100000;
	vector<int> v;
	v.reserve(N);
	srand(time(0));
	for (size_t i = 0; i < N; i++)
	{
		v.push_back(rand() + i);
	}
	size_t begin2 = clock();
	AVL::AVLTree<int, int> t;
	for (auto e : v)
	{
		t.Insert(e, e);
	}
	size_t end2 = clock();
	cout << "Insert:" << end2 - begin2 << endl;
	cout << t.IsBalanceTree() << endl;
	cout << "Height:" << t.Height() << endl;
	cout << "Size:" << t.Size() << endl;
	size_t begin1 = clock();
	// 确定在的值
	/*for (auto e : v)
	{
	t.Find(e);
	}*/
	// 随机值
	for (size_t i = 0; i < N; i++)
	{
		t.Find((rand() + i));
	}
	size_t end1 = clock();
	cout << "Find:" << end1 - begin1 << endl;
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

后言

这就是AVL树的深度剖析。大家自己好好消化!今天就分享到这!感谢各位的耐心垂阅!咱们下期见!拜拜~

data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/2301_81670477/article/details/144308070","extend1":"pc","ab":"new"}">> id="blogExtensionBox" style="width:400px;margin:auto;margin-top:12px" class="blog-extension-box"> class="blog_extension blog_extension_type2" id="blog_extension"> class="extension_official" data-report-click="{"spm":"1001.2101.3001.6471"}" data-report-view="{"spm":"1001.2101.3001.6471"}"> class="blog_extension_card_left"> class="blog_extension_card_cont"> 大白的编程日记 class="blog_extension_card_cont_r"> 微信名片
注:本文转载自blog.csdn.net的PlutoZuo的文章"https://blog.csdn.net/PlutoZuo/article/details/133636059"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接

评论记录:

未查询到任何数据!