AVL树的插入和删除

#pragma once
#include<stack>

#include<iostream>
using namespace std;


template<class Type>
class AVLTree;

template<class Type>
class AVLNode
{
	friend class AVLTree<Type>;
public:
	AVLNode() :data(0), leftChild(NULL), rightChild(NULL), bf(0)
	{}
	AVLNode(Type d) :data(d), leftChild(NULL), rightChild(NULL), bf(0)
	{}
	~AVLNode()
	{}

private:
	Type data;
	int bf;
	AVLNode<Type>*leftChild;
	AVLNode<Type>*rightChild;

};
template<class Type>
class AVLTree
{
public:
	AVLTree() :root(NULL)
	{}
public:
	bool Insert(Type &x)
	{
		return Insert(root, x);
	}
	bool Remove( Type x)
	{
		return Remove(root, x);
	}
	void sort()
	{
		sort(root);
	}
	
protected:
	void sort(AVLNode<Type>*t)const
	{
		if (t != NULL)
		{
			sort(t->leftChild);
			cout << t->data << " ";
			sort(t->rightChild);

		}
	}
	bool Insert(AVLNode<Type>*&t, Type x)
	{
		AVLNode<Type> *p = t;
		AVLNode<Type> *pr = NULL;//代表新增加节点的父节点
		stack<AVLNode<Type>* >st;
		while (p != NULL)//寻找插入位置,p为根
		{
			pr = p;
			st.push(pr);
			if (x < p->data)
				p = p->leftChild;
			else if (x > p->data)
				p = p->rightChild;
			else
				return false;
		}
		p = new AVLNode<Type>(x);
		if (pr == NULL)//空树,新节点为根节点(判断新节点有没有父节点

,即如果没有父节点,就为根节点)
		{
			t = p;
			return true;
		}
		if (x < pr->data)
		{
			pr->leftChild = p;
		}
		else
		{
			pr->rightChild = p;
		}
		while (!st.empty())//比较难理解的是 p,pr 每次循环后与插入值之

间的关系,容易搞混(限于此循环)
		{
			pr = st.top();
			st.pop();
			if (p == pr->leftChild)
				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)
					{
						RotateL(pr);
					}
					else
					{
						RotateRL(pr);

					}
				}
				else
				{
					if (p->bf < 0)
					{
						RotateR(pr);
					}
					else
					{
						RotateLR(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;
		}

	}
	bool Remove(AVLNode<Type>*&t, Type &x)//p为要删除的节点
	{
		AVLNode<Type>*p = t;
		AVLNode<Type>*pr = NULL;
		stack<AVLNode<Type>*> st;
		while (p != NULL)//找到要删除的节点p
		{
			if (x == p->data)
				break;
			pr = p;
			st.push(pr);
			if (x > p->data)
				p = p->rightChild;
			else
				p = p->leftChild;
		}
		if (p == NULL)//被删节点不存在
			return false;

		AVLNode<Type>*q = NULL;
		if (p->leftChild != NULL&&p->rightChild != NULL)//被删节点有

两个子女,最终转换为只有一个子女
		{
			pr = p;
			st.push(pr);
 			q = p->leftChild;;//中序遍历的前驱(左子树中找最小的

)
			while (q->rightChild != NULL)
			{
				pr = q;
				st.push(pr);
				q = q->rightChild;
			}
			p->data = q->data;//用q的值填补p   发现一个秘密:循环

完后栈的元素为3个,比如依次入栈的元素为11,18,15,执行完这句后栈的元素更改,

更改的元素为18,栈的元素为11,16,15,入栈之后也可以通过指针更改栈的元素,在

最后连接时,使用的出栈元素为更新值
			p = q;//p永远是要删除的节点
		}
		if (p->leftChild != NULL)//1.转换的要删除节点已找到,要将将这

个删除节点转换,即判断这个要删除的节点有没有左右孩子( q指向p左子树代替或右子

树代替,删除p)
			q = p->leftChild;
		else
			q = p->rightChild;

		if (pr == NULL)//被删除节点为根节点
			t = q;
		else
		{
			if (pr->leftChild == p)//2.p(转化的要删节点)的父要重

新连接,即删除节点的父与删除节点的左孩子或者右孩子连接
				pr->leftChild = q;
			else
				pr->rightChild = q;

			

/
			//bf(调整平衡因子)
			while (!st.empty())
			{
				pr = st.top();
				st.pop();
				if (pr->leftChild == q&&q != NULL)
					pr->bf++;
				else  if ((pr->rightChild == q&&q != NULL) || 

q == NULL)
					pr->bf--;


				if (pr->bf == 1 || pr->bf == -1)
					break;
				else if (pr->bf == 0)//重新回溯
					q = pr;
				else//较矮子树被缩短
				{
					//q指向较高子树的根
					if (pr->bf > 0)
						q = pr->rightChild;
					else
						q = pr->leftChild;

					if (q->bf == 0)
					{
						if (pr->bf > 0)
						{
							RotateL(pr);
							pr->bf = -1;
							pr->leftChild->bf = 

1;
						}
						else
						{
							RotateR(pr);
							pr->bf = 1;
							pr->rightChild->bf = 

-1;
						}
					}
					else//q->bf和pr->bf相同或相反
					{
						if (q->bf<0 && pr->bf<0)
						{
							RotateR(pr);
						}
						else if (q->bf>0 && pr->bf>0)
						{
							RotateL(pr);
						}
						else if (q->bf<0 && pr->bf>0)
						{
							RotateRL(pr);
						}
						else if (q->bf>0 && pr->bf<0)
						{
							RotateLR(pr);
						}
					}
					break;
				}
			}

			if (st.empty())//调整新根
				t = pr;
			else//链接调整后的
			{
				AVLNode<Type> *tmp = st.top();
				if (tmp->data > pr->data)
					tmp->leftChild = pr;
				else
					tmp->rightChild = pr;

			}
		}
		delete p;//p为删除的节点
		return true;
	}
protected:
       //ptr均指不平衡的节点,SUBR,SUBL均为调整后新根的右,左子树
	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 RotateR(AVLNode<Type> *&ptr)
	{
		AVLNode<Type> *subR = ptr;
		ptr = subR->leftChild;
		subR->leftChild = ptr->rightChild;
		ptr->rightChild = subR;
		ptr->bf = subR->bf = 0;
	}
	void RotateLR(AVLNode<Type> *&ptr)
	{
		AVLNode<Type> *subR = ptr;
		AVLNode<Type> *subL = subR->leftChild;
		ptr = subL->rightChild;

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

		if (ptr->bf <= 0)
			subL->bf = 0;
		else
			subL->bf = -1;

		subR->leftChild = ptr->rightChild;
		ptr->rightChild = subR;


		if (ptr->bf < 0)
			subR->bf = 1;
		else
			subR->bf = 0;

		ptr->bf = 0;
	}
	void RotateRL(AVLNode<Type> *&ptr)
	{
		AVLNode<Type>*subL = ptr;
		AVLNode<Type>*subR = subL->rightChild;
		ptr = subR->leftChild;
		subR->leftChild = ptr->rightChild;
		ptr->rightChild = subR;
		if (ptr->bf >=0)
			subR->bf = 0;
		else
			subR->bf = 1;
		subL->rightChild = ptr->leftChild;
		ptr->leftChild = subL;
		if (ptr->bf >0)
			subL->bf = -1;
		else
			subL->bf = 0;
		ptr->bf = 0;
	}
private:
	AVLNode<Type>*root;
};
#include<iostream>
using namespace std;
void main()
{
	int ar[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
	//int ar[] = {50,30,70,10,35,60,80,32,38};
	//int ar[] = {10, 20};
	int n = sizeof(ar) / sizeof(int);
	AVLTree<int>  avl;
	for (int i = 0; i < n; ++i)
	{
		avl.Insert(ar[i]);
	}
	avl.sort();
	cout << endl;
	avl.Remove(18);
	avl.sort();

	return;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值