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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章