【數據結構】平衡二叉樹(AVL樹)的定義、構建和插入操作

一、定義

    平衡二叉樹,又稱AVL樹。它或者是一棵空樹,或者是具有下列性質的二叉樹:它的左子樹和右子樹都是平衡二叉樹,且左子樹和右子樹的高度之差的絕對值不超過1。將二叉樹上的結點的平衡因子定義爲該節點的右子樹的高度減去它的左子樹的高度,則AVL樹上所有結點的平衡因子只可能是1、-1和0。只要AVL樹上有一個結點的平衡因子的絕對值大於1,則該AVL樹就是不平衡的。

    引入AVL樹的原因:對於一般的BST樹,其期望高度和操作的時間複雜度是O(logn)。不過可能存在這種情況,在插入的數據有序時,BST樹將退化成單分支,此時其操作的時間複雜度退化爲O(n)。我們可以通過建立AVL樹來避免這種情況。

二、AVL樹的定義、構建和插入操作

    1.定義AVL樹的結構

typedef int KeyType;

//定義AVL樹結構
struct AVLNode
{
	AVLNode *leftchild;
	AVLNode *parent;//定義雙親是爲了回溯
	AVLNode *rightchild;
	int balance;
	KeyType key;
};

typedef struct
{
	AVLNode *head;
	int cursize;
}AVLTree;

    2.購買釋放結點 

//購買一個節點
AVLNode* BuyNode(AVLNode *pa = NULL)
{
	AVLNode *s = (AVLNode *)malloc(sizeof(AVLNode));
	if(NULL == s)
	{
		exit(1);
	}
	memset(s,0,sizeof(AVLNode));
	s->parent = pa;
	s->balance = 0;

	return s;
}

//釋放節點
void FreeNode(AVLNode *ptr)
{
	free(ptr);
}

    3.初始化AVL樹

//初始化AVL樹
void InitAVLTree(AVLTree &myt)
{
	myt.head = BuyNode(); // head // root;
	myt.cursize = 0;
}

    4.平衡化旋轉

    平衡化旋轉有兩類:單旋轉(左旋、右旋)和雙旋轉(左平衡、右平衡)

//左單旋
void RotateLeft(AVLNode *head,AVLNode *ptr)
{
	//先變孩子,後變雙親
	AVLNode *newroot = ptr->rightchild;
	newroot->parent = ptr->parent;
	if(ptr == head->parent)
	{
		head->parent = newroot;
	}
	else
	{
		if(ptr->parent->leftchild == ptr)
		{
			ptr->parent->leftchild = newroot;
		}
		else
		{
			ptr->parent->rightchild = newroot;
		}
	}
	ptr->rightchild = newroot->leftchild;
	if(newroot->leftchild != NULL)
	{
		newroot->leftchild->parent = ptr;
	}
	newroot->leftchild = ptr;
	ptr->parent = newroot;

}

//右單旋
void RotateRight(AVLNode *head,AVLNode *ptr)
{
	AVLNode *newroot = ptr->leftchild;
	newroot->parent = ptr->parent;
	if(ptr == head->parent)
	{
		head->parent = newroot;
	}
	else
	{
		if(ptr->parent->leftchild == ptr)
		{
			ptr->parent->leftchild = newroot;
		}
		else
		{
			ptr->parent->rightchild = newroot;
		}
	}
	ptr->leftchild = newroot->rightchild;
	if(newroot->rightchild != NULL)
	{
		newroot->rightchild->parent = ptr;
	}
	newroot->rightchild = ptr;
	ptr->parent = newroot;
}

//左平衡
void BalanceLeft(AVLTree &myt,AVLNode *ptr)
{
	AVLNode *leftsub = ptr->leftchild;
	AVLNode *rightsub = NULL;

	switch(leftsub->balance)
	{
	case 0:
		cout << "left already balance" << endl;
		break;
	case 1:
		ptr->balance = 0;
		leftsub->balance = 0;
		//三個結點處於一條直線上,則採用單旋轉進行平衡,分爲左單旋和右單旋
		RotateRight(myt.head,ptr);
		break;
	case -1:
		//三個結點處於一條折線上,則採用雙旋轉進行平衡,分爲左先左後右和先右後左
		rightsub = leftsub->rightchild;
		switch(rightsub->balance)
		{
		case 0:
			ptr->balance = 0;
			leftsub->balance = 0;
			break;
		case 1:
			ptr->balance = 0;
			leftsub->balance = -1;
			break;
		case -1:
			ptr->balance = 1;
			leftsub->balance = 0;
			break;
		}
		rightsub->balance = 0;
		RotateLeft(myt.head,leftsub);
		RotateRight(myt.head,ptr);
		break;
	}
}

//右平衡
void BalanceRight(AVLTree &myt,AVLNode *ptr)
{
	AVLNode *rightsub = ptr->rightchild;
	AVLNode *leftsub = NULL;

	switch(rightsub->balance)
	{
	case 0:
		cout << "right already balance" << endl;
		break;
	case 1:
		ptr->balance = 0;
		rightsub->balance = 0;
		RotateLeft(myt.head,ptr);
		break;
	case -1:
		leftsub = rightsub->leftchild;
		switch(leftsub->balance)
		{
		case 0:
			ptr->balance = 0;
			rightsub->balance = 0;
			break;
		case 1:
			ptr->balance = -1;
			rightsub->balance = 0;
			break;
		case -1:
			ptr->balance = 0;
			rightsub->balance = 1;
			break;
		}
		leftsub->balance = 0;
		RotateRight(myt.head,rightsub);
		RotateLeft(myt.head,ptr);
		break;
	}
}

     5.調整平衡二叉樹

//調整平衡二叉樹
void Adjust_Balace(AVLTree &myt,AVLNode *ptr)
{
	AVLNode *pParent = ptr->parent;
	AVLNode *p = ptr;

	//從插入位置往根回溯,檢查各結點的平衡因子
	bool tag = true;
	for( ;tag && pParent != myt.head; )
	{
		if(pParent->leftchild == p)
		{
			switch(pParent->balance)
			{
			case 0:
				pParent->balance = -1;
				break;
			case 1:
				pParent->balance = 0;
				tag = false;//高度並未變化並不需要調整
				break;
			case -1:
				BalanceLeft(myt,pParent);
				//不會引起連級調整(即不會回溯調整),因爲:
				//1.插入數據前該樹已平衡,即爲AVL樹;
				//2.插入一個值之後平衡因子絕對值最多爲2,只需調整一次,即達到整棵樹平衡
				tag = false;
				break;
			}
		}
		else
		{
			switch(pParent->balance)
			{
			case 0:
				pParent->balance = 1;
				break;
			case -1:
				pParent->balance = 0;
				tag = false;
				break;
			case 1:
				BalanceRight(myt,pParent);
				tag = false;
				break;
			}
		}
		p = pParent;
		pParent = pParent->parent;
	}
}

    6.向AVL樹中插入元素

//向AVL樹中插入元素
bool InsertItem(AVLTree &myt,KeyType kx)
{
	AVLNode *pa = myt.head;//head
	AVLNode *p = myt.head->parent;//root

	while(NULL != p && p->key != kx)
	{
		pa = p;
		p = (p->key > kx) ? p->leftchild : p->rightchild;
	}

	if(NULL != p && p->key == kx)
	{
		return false;
	}

	p = BuyNode(pa);
	p->key = kx;
	if(pa == myt.head)
	{
		myt.head->parent = p;
		myt.head->leftchild = p;
		myt.head->rightchild = p;
	}
	else
	{
		if(pa->key > p->key)
		{
			pa->leftchild = p;
			if(myt.head->leftchild->key > p->key)
			{
				myt.head->leftchild = p;
			}
		}
		else
		{
			pa->rightchild = p;
			if(myt.head->rightchild->key < p->key)
			{
				myt.head->rightchild = p;
			}
		}

		Adjust_Balace(myt,p);
	}
	myt.cursize += 1;

	return true;
}

    7.非遞歸中序遍歷AVL樹

//找到某結點的最左結點
AVLNode *First(AVLNode *ptr)
{
	while(ptr != NULL && ptr->leftchild != NULL)
	{
		ptr = ptr->leftchild;
	}
	return ptr;
}

//找到某結點的下一個結點
AVLNode *Next(AVLTree &myt,AVLNode *ptr)
{
	if(ptr == NULL || ptr == myt.head) return NULL;
	if(ptr->rightchild != NULL)
	{
		return First(ptr->rightchild);
	}
	else
	{
		AVLNode *pa = ptr->parent;
		while(pa != myt.head && pa->leftchild != ptr)
		{
			ptr = pa;
			pa = pa->parent;
		}
		if(pa == myt.head)
		{
			pa = NULL;
		}
		return pa;
	}
}

//非遞歸中序遍歷
void NiceInOrder(AVLTree &bst)
{
	for(AVLNode *p = First(bst.head->parent);
		p != NULL ; p = Next(bst,p))
	{
		cout<<p->key<<" ";
	}
	cout<<endl;
}

 

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