c++学习第十八天

创作过程中难免有不足,若您发现本文内容有误,恳请不吝赐教。


提示:以下是本篇文章正文内容,下面案例可供参考。

一、AVL树

  1.AVL树的概念

        如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在O(logN),搜索时间复杂度O(logN)


  2.AVL树节点的定义

//AVLTree.h"

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

  3.AVL树的插入

     AVL 树就是在二叉搜索树的基础上引入了平衡因子,因此 AVL 树也可以看成是二叉搜索树。那么
AVL 树的插入过程可以分为两步:
         ①. 按照二叉搜索树的方式插入新节点                            ②. 调整节点的平衡因子
//AVLTree.h"

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* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->left;
			}
			else if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->right;
			}
			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;
		}
		while (parent)
		{
			if (cur == parent->left)
				parent->bf--;
			else if (cur == parent->right)
				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);     //先左单旋再右单旋
				// 1、旋转让这颗子树平衡了
				// 2、旋转降低了这颗子树的高度,恢复到跟插入前一样的高度,
                //  所以对上一层没有影响,不用继续更新
				break;
			}
			else
				assert(false);
		}
		return true;
	}
private:
	Node* _root = nullptr;
};

  4.AVL树的旋转

新节点插入较高右子树的右侧---右右:左单旋

void RotateL(Node* parent)  //左单旋
{
	Node* subR = parent->right;
	Node* subRL = subR->left;
	parent->right = subRL;
	if (subRL)       //subRL有可能为空
		subRL->_parent = parent;
	Node* parentParent = parent->_parent;      //记录parent的父亲
	subR->left = parent;
	parent->_parent = subR;
	if (_root == parent)     //parent原来是根节点
	{
		_root = subR;
		subR->_parent = nullptr;
	}
	else                    //parent原来不是根节点
	{
		if (parentParent->left == parent)    //parent原来在父节点的左子树
			parentParent->left = subR;
		else                                 //parent原来在父节点的右子树
			parentParent->right = subR;
		subR->_parent = parentParent;
	}
	parent->bf = subR->bf = 0;
}

新节点插入较高左子树的左侧---左左:右单旋(和左单旋类似)

void RotateR(Node* parent)   //右单旋
{
	Node* subL = parent->left;
	Node* subLR = subL->right;
    parent->left = subLR;
	if (subLR)
		subLR->_parent = parent;
	Node* parentParent = parent->_parent;
	subL->right = parent;
	parent->_parent = subL;
	if (_root == parent)
	{
		_root = subL;
		subL->_parent = nullptr;
	}
	else
	{
		if (parentParent->left == parent)
			parentParent->left = subL;
		else
			parentParent->right = subL;

		subL->_parent = parentParent;
	}
	subL->bf = parent->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 == 0)
		// subRL自己就是新增
		parent->bf = subR->bf = subRL->bf = 0;
	else if (bf == 1)
	{
		// subRL的右子树新增
		parent->bf = -1;
		subRL->bf = 0;
		subR->bf = 0;
	}
	else if (bf == -1)
	{
		// subRL的左子树新增
		parent->bf = 0;
		subRL->bf = 0;
		subR->bf = 1;
	}
	else
		assert(false);
}

新节点插入较高左子树的右侧---左右:先左单旋再右单旋(与情况③类似)

void RotateLR(Node* parent)    //先左单旋再右单旋
{
	Node* subL = parent->left;
	Node* subLR = subL->right;
	int bf = subLR->bf;
	RotateL(parent->left);
	RotateR(parent);
	if (bf == 0)
		// subRL自己就是新增
		parent->bf = subL->bf = subLR->bf = 0;
	else if (bf == 1)
	{
		// subLR的右子树新增
		parent->bf = 0;
			subLR->bf = 0;
		subL->bf = -1;
	}
	else if (bf == -1)
	{
		// subLR的左子树新增
		parent->bf = 1;
		subLR->bf = 0;
		subL->bf = 0;
	}
	else
		assert(false);
}

  5.AVL树的验证

验证其为二叉搜索树

      如果中序遍历可得到一个有序的序列,就说明为二叉搜索树。
//中序遍历代码
void InOrder()
{
	_InOrder(_root);
	cout << endl;
}
void _InOrder(Node* root)
{
	if (root == nullptr)
		return;
	_InOrder(root->left);
	cout << root->_kv.first << " ";
	_InOrder(root->right);
}

验证其为平衡树

    Ⅰ.每个节点子树高度差的绝对值不超过 1( 注意节点中如果没有平衡因子 )
    Ⅱ.节点的平衡因子是否计算正确
//计算子树高度
int _Height(Node* root)
{
	if (root == nullptr)
		return false;
	int leftHeight = _Height(root->left);
	int rightHeight = _Height(root->right);
	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

bool IsBalance()
{
	return _IsBalance(_root);
}
bool _IsBalance(Node* root)
{
	if (root == nullptr)
		return true;
	int leftHeight = _Height(root->left);
	int rightHeight = _Height(root->right);
	if (rightHeight - leftHeight != root->bf)
	{
		cout << root->_kv.first << "平衡因子异常" << endl;
		return false;
	}
	return abs(rightHeight - leftHeight) < 2
		&& _IsBalance(root->left)
		&& _IsBalance(root->right);
}

③验证结果

//Test.cpp
#include<iostream>
#include<vector>
using namespace std;

#include"AVLTree.h"

int main()
{
	int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
	AVLTree<int, int> t;
	for (auto e : a)
		t.Insert(make_pair(e, e));
	t.InOrder();
	cout << t.IsBalance() << endl;

	return 0;
}


总结

   以上就是今天要讲的内容,本文仅仅简单介绍了c++的基础知识。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jacob~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值