c++复习笔记18-AVL树(插入+删除)

 AVL树:

        二叉搜索树虽可以缩短查找的效率,但 如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下 。因此,两位俄罗斯的数学家 G.M.Adelson-Velskii E.M.Landis 1962 发明了一种解决上述问题的方法: 当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之 差的绝对值不超过 1( 需要对树中的结点进行调整 ) ,即可降低树的高度,从而减少平均搜索长度。
        一棵 AVL 树或者是空树,或者是具有以下性质的二叉搜索树:
它的左右子树都是 AVL
左右子树高度之差 ( 简称平衡因子 ) 的绝对值不超过 1(-1/0/1)
         如果一棵二叉搜索树是高度平衡的,它就是 AVL 树。如果它有 n 个结点,其高度可保持在O(log2n) ,搜索时 间复杂度 O(log2n )
AVL树的插入:
     
        AVL 树就是在二叉搜索树的基础上引入了平衡因子,因此 AVL 树也可以看成是二叉搜索树。那么 AVL 树的插入过程可以分为两步:
1. 按照二叉搜索树的方式插入新节点
2. 调整节点的平衡因子
AVL树的旋转:
        如果在一棵原本是平衡的 AVL 树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,使之平衡 化。根据节点插入位置的不同, AVL 树的旋转分为四种:
1. 新节点插入较高左子树的左侧 --- 左左:右单旋
2. 新节点插入较高右子树的右侧 --- 右右:左单旋
3. 新节点插入较高左子树的右侧 --- 左右:先左单旋再右单旋

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

参考右左双旋。
总结:假如以 pParent 为根的子树不平衡,即 pParent 的平衡因子为 2 或者 -2 ,分以下情况考虑
1. pParent 的平衡因子为 2 ,说明 pParent 的右子树高,设 pParent 的右子树的根为 pSubR
     当 pSubR 的平衡因子为 1 时,执行左单旋
     当 pSubR 的平衡因子为 -1 时,执行右左双旋
2. pParent 的平衡因子为 -2 ,说明 pParent 的左子树高,设 pParent 的左子树的根为 pSubL
     当 pSubL 的平衡因子为 -1 是,执行右单旋
     当 pSubL 的平衡因子为 1 时,执行左右双旋
旋转完成后,原 pParent 为根的子树个高度降低,已经平衡,不需要再向上更新。
AVL树的删除:删除情况较为复杂,通常AVL树的考察重点是插入,下面的删除代码与插入代码呼应,可以体会揣摩。
AVL树的性能:
       AVL 树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过 1 ,这样可以保证查询时高效的时间复杂度,即log2N 。但是如果要对 AVL 树做一些结构修改的操作,性能非常低下,比如:
 插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。 因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的 ( 即不会改变 ) ,可以考虑 AVL 树, 但一个结构经常修改,就不太适合。
#include<iostream>
#include<vector>
#include<stack>
using namespace std;

template<class Type>
class AVLTree;

template<class Type>
class AVLNode
{
friend class AVLTree<Type>;
public:
	AVLNode() :data(Type()), leftChild(nullptr), rightChild(nullptr), bf(0) {}
	AVLNode(Type d,AVLNode* left=nullptr,AVLNode* right=nullptr):data(d),leftChild(left),rightChild(right),bf(0){}
	~AVLNode() {}
private:
	Type data;
	AVLNode* leftChild;
	AVLNode* rightChild;
	int bf;
};

template<class Type>
class AVLTree
{
public:
	AVLTree() :root(nullptr) {}

	bool Insert(const Type& x)
	{
		return Insert(root, x);
	}

	bool Remove(const Type& key)
	{
		return Remove(root, key);
	}
protected:
	bool Insert(AVLNode<Type>*& t, const Type& x);
	bool Remove(AVLNode<Type>*& t, const Type& key);

	void RotateL(AVLNode<Type>*& ptr)
	{
		AVLNode<Type>* subL = ptr;
		ptr = subL->rightChild;

		subL->rightChild = ptr->leftChild;
		ptr->leftChild = subL;
		ptr->bf = subL->bf = 0;

	}

	void RotateLR(AVLNode<Type>*& ptr)
	{
		AVLNode<Type>* subL, * subR;
		subR = ptr;
		subL = ptr->leftChild;
		ptr = subL->rightChild;

		//L
		subL->rightChild = ptr->leftChild;
		ptr->leftChild = subL;
		//调整 subL bf
		if (ptr->bf <= 0)
			subL->bf = 0;
		else
			subL->bf = -1;

		//R
		subR->leftChild = ptr->rightChild;
		ptr->rightChild = subR;
		//调整 subR bf
		if (ptr->bf >= 0)
			subR->bf = 0;
		else
			subR->bf = 1;

		ptr->bf = 0;
	}

	void RotateR(AVLNode<Type>*& ptr)
	{
		AVLNode<Type>* subR = ptr;
		ptr = subR->leftChild;

		subR->leftChild = ptr->rightChild;
		ptr->rightChild = subR;
		ptr->bf = subR->bf = 0;
	}
	void RotateRL(AVLNode<Type>*& ptr)
	{
		AVLNode<Type>* subL, * subR;
		subL = ptr;
		subR = ptr->rightChild;
		ptr = subR->leftChild;

		//R
		subR->leftChild = ptr->rightChild;
		ptr->rightChild = subR;
		if (ptr->bf >= 0)
			subR->bf = 0;
		else
			subR->bf = 1;

		//L
		subL->rightChild = ptr->leftChild;
		ptr->leftChild = subL;
		if (ptr->bf <= 0)
			subL->bf = 0;
		else 
			subL->bf = -1;
	}

private:
	AVLNode<Type>* root;
};

template<class Type>
bool AVLTree<Type>::Insert(AVLNode<Type>*& t, const Type& x)
{
   //1 先按照BST树插入结点
	AVLNode<Type>* p = t;
	AVLNode<Type>* pr = nullptr;
	stack<AVLNode<Type>*>st;

	while (p != nullptr)
	{
		if (x == p->data)
			return false;

		pr = p;
		st.push(pr);

		if (x < p->data)
			p = p->leftChild;
		else
			p = p->rightChild;
	}

	p = new AVLNode<Type>(x);
	if (pr == nullptr)
	{
		t = p;
		return true;
	}
	if (p->data < pr->data)
		pr->leftChild = p;
	else
		pr->rightChild = p;

   //2 调整平衡
	while (!st.empty())
	{
		pr = st.top();
		st.pop();
		if (pr->leftChild == p)
			pr->bf--;
		else
			pr->bf++;

		if (pr->bf == 0)
			break;//结束调整
		else if (pr->bf == 1 || pr->bf == -1)
			p = pr;//向上回溯

		else
		{
			//不平衡,需要调整平衡
			if (pr->bf < 0)
			{
				if (p->bf < 0)
				{
					//cout << "RotateR." << endl;
					RotateR(pr);
				}
				else
				{
					//cout << "PotateLR." << endl;
					RotateLR(pr);
				}
			}
			else
			{
				if (p->bf > 0)
				{
					//cout << "RotateL." << endl;
					RotateL(pr);
				}
				else
				{
					//cout << "RotateRL." << endl;
					RotateRL(pr);
				}
			}
			break;
		}
	}

	if (st.empty())
		t = pr;
	else
	{
		AVLNode<Type>* q = st.top();
		if (pr->data < q->data)
			q->leftChild = pr;
		else
			q->rightChild = pr;
	}

	return true;
}

template<class Type>
bool AVLTree<Type>::Remove(AVLNode<Type>*& t, const Type& key)
{
	//1根据BST删除节点
	AVLNode<Type>* pr = nullptr;
	AVLNode<Type>* p = t, * q = nullptr;
	AVLNode<Type>* Nil = new AVLNode<Type>(0);

	stack<AVLNode<Type>*>st;
	while (p != nullptr)
	{
		if (p->data == key)
			break;
		pr = p;
		st.push(pr);
		if (key < p->data)
			p = p->leftChild;
		else
			p = p->rightChild;
	}

	if (p == nullptr)
		return false;

	if (p->leftChild != nullptr && p->rightChild != nullptr)
	{
		q = p->leftChild;
		pr = p;
		st.push(pr);
		while (q->rightChild != nullptr)
		{
			pr = q;
			st.push(pr);
			q = q->rightChild;
		}
		p->data = q->data;
		p = q;
	}

	//p是要删除的节点,q是p的子女节点
	if (p->leftChild != nullptr)
		q = p->leftChild;
	else if (p->rightChild != nullptr)
		q = p->rightChild;
	else
		q = Nil;

	bool isLeftChild = false;

	if (pr == nullptr)
		t = q;
	else
	{
		if (p == pr->leftChild)
		{
			if (q != Nil)
				pr->leftChild = q;
			else
				pr->leftChild = nullptr;
			isLeftChild = true;
		}
		else if (q != Nil)
			pr->rightChild = q;
		else
			pr->rightChild = nullptr;
	}

	//2平衡BST树
	while (!st.empty())
	{
		pr = st.top();
		st.pop();

		if (q == pr->leftChild || isLeftChild)
			pr->bf++;
		else
			pr->bf--;

		//考察pr平衡因子
		if (pr->bf == 1 || pr->bf == -1)
			break;
		else if (pr->bf == 0)
			q = pr;

		else
		{
			//|bf|=2
			//让q指向pr较高的子树
			if (pr->bf < 0)
				q = pr->leftChild;//左树高
			else
				q = pr->rightChild;//右树高

			if (q->bf == 0)
			{
				if (pr->bf < 0)
				{
					RotateR(pr);
					pr->bf = 1;
					pr->rightChild->bf = -1;
				}
				else
				{
					RotateL(pr);
					pr->bf = -1;
					pr->leftChild->bf = 1;
				}
			}

			else if (pr->bf < 0)
			{
				if (q->bf < 0) // /
				{
					RotateR(pr);
				}

				else
				{
					RotateLR(pr);//<
				}
			}

			else if (pr->bf > 0)
			{
				if (q->bf < 0)
				{
					RotateRL(pr);  //>
				}

				else
				{
					RotateL(pr);// \ 
				}
			}

			//重新连接
			if (st.empty())
				t = pr;
			else
			{
				q = st.top();
				if (pr->data < q->data)
					q->leftChild = pr;
				else
					q->rightChild = pr;
			}
				break;
		}
	}
	delete p;
	return true;
}


void test01()
{
	vector<int> iv{ 16,3,7,11,9,26,18,14,15 };
	AVLTree<int>avl;
	for (const auto& e : iv)
	avl.Insert(e);
	avl.Remove(3);
	avl.Remove(9);
	//avl.Remove(7);
	cout << "OK" << endl;
}

void main()
{
	test01();
	system("pause");
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值