《大話數據結構》C++實現二叉平衡樹的建立

平衡二叉搜索樹(Self-balancing binary search tree)又被稱爲AVL樹(有別於AVL算法),且具有以下性質:它是一 棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹都是一棵平衡二叉樹,同時,平衡二叉樹必定是二叉排序樹。

高度差可以用平衡因子bf來定義,我們用左子樹的高度減去右子樹的高度來表示bf,即-1<|bf|<1。

引入平衡二叉樹是由於二叉排序樹,在某些情況會導致樹的高度一直的增加,比如一組有序的數據,在查找或創建時遞歸層級會很深,導致方法棧容易溢出。

平衡二叉樹是通過旋轉來緩解樹高度增加過快的情況。

先介紹下最小不平衡節點的概念:插入一個節點之後,距離這個插入節點最近的不平衡節點就是最小不平衡節點。就是說在遞歸插入節點後,開始回溯,碰到的第一個不平衡的節點就是最小不平衡節點。

當最小不平衡節點右子樹高則需要左旋,左子樹高則需要右旋(還有些情況需要先對其左/右子樹旋轉)。

思考:

1、既然旋轉是通過平衡因子|bf|>1來決定怎麼旋轉的,那麼在旋轉前這些平衡因子是什麼時候賦值的呢?

2、旋轉之後,哪些節點需要調整?,平衡因子又改如何調整呢?

下圖只列出左子樹高的幾種情況,T表示最小不平衡節點,L表示其左子樹,LR表示L的右子樹,

爲了形象用EH(0),LH(1),RH(-1)分別表示某一節點 左右子樹相等、左子樹高、右子樹高三種情況。

根據L節點的左右子樹高度差來確定直接右旋還是先左旋再右旋,因爲L爲最小不平衡子樹的左子樹,故不會出現L.bf=EH的情況。

一、L.bf=LH

右旋:

旋轉之後T.bf=L.bf=EH

二、L.bf=RH

先左旋再右旋:

當L的平衡因子爲-1時則需要先對L進行右旋,然後再對T進行左旋。根據LR的情況再分爲下面三種(因爲旋轉兩次,那麼最後最小不平衡子樹的根節點爲LR,並且LR.bf=EH

1、 LR=EH

 

 

旋轉之後T.bf=L.bf=EH

2、 LR=LH

 

旋轉之後T.bf=RH, L.bf=EH

3、 LR=RH

 

旋轉之後T.bf=EH, L.bf=LH

代碼如下:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>

using namespace std;

typedef int Status;

constexpr auto LH = +1;
constexpr auto EH = 0;
constexpr auto RH = -1;


//定義平衡二叉樹的節點結構(在二叉排序樹中加入一個bf來存儲平衡因子)
typedef struct BiTNode
{
	int data;
	int bf;
	struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;


void R_Rotate(BiTree* p);
void L_Rotate(BiTree* p);
void LeftBalance(BiTree *T);
void RightBalance(BiTree* T);
void InOrderTraverse(BiTree *T);
Status InsertAVL(BiTree *T,int e,Status *taller);


//進行二叉平衡樹時的右旋操作
void R_Rotate(BiTree *p)
{
	BiTree L;
	L = (*p)->lchild;
	(*p)->lchild = L->rchild;
	L->rchild = *p;
	*p = L;
}


//進行二叉平衡樹時的左旋操作
void L_Rotate(BiTree *p)
{
	BiTree R;
	R = (*p)->rchild;
	(*p)->rchild = R->lchild;
	R->lchild = (*p);
	*p = R;
}

//構建二叉平衡樹時左邊太“重”,進行左平衡處理函數
void LeftBalance(BiTree* T)
{
	BiTree L, Lr;
	L = (*T)->lchild;
	switch (L->bf)
	{/*檢查T的左子樹的平衡度,並做相應的處理*/
	case LH:/*新節點插入在了T的左孩子的左子樹上,只要做單左旋處理*/
		(*T)->bf = L->bf = EH;
		R_Rotate(T);
		break;
	case RH:/*新節點插入在了T的左孩子的右子樹上,要做雙旋處理,
			通過判斷T的左孩子的右子樹的根節點的bf來決定進行雙旋處理後各自的bf值*/
		Lr = L->rchild;
		switch (Lr->bf)
		{
		case LH:
			(*T)->bf = RH;
			L->bf = EH;
			break;
		case EH:
			(*T)->bf = L->bf = EH;
			break;
		case RH:
			(*T)->bf = EH;
			L->bf = LH;
			break;
		}
		Lr->bf = EH;
		L_Rotate(&(*T)->lchild);
		R_Rotate(T);
	}
}

//構建二叉平衡樹時右邊太“重”,進行右平衡處理函數
void RightBalance(BiTree* T)
{
	BiTree R, Rl;
	R = (*T)->rchild;
	switch (R->bf)
	{/*檢查T的右子樹的平衡度,並做相應的處理*/
	case RH:/*新節點插入在了T的右孩子的右子樹上,只要做單左旋處理*/
		(*T)->bf = R->bf = EH;
		L_Rotate(T);
		break;
	case LH:/*新節點插入在了T的右孩子的左子樹上,要做雙旋處理,
			通過判斷T的右孩子的左子樹的根節點的bf來決定進行雙旋處理後各自的bf值*/
		Rl = R->lchild;
		switch (Rl->bf)
		{
		case LH:
			(*T)->bf = EH;
			R->bf = RH;
			break;
		case EH:
			(*T)->bf = R->bf = EH;
			break;
		case RH:
			(*T)->bf = LH;
			R->bf = EH;
			break;
		}
		Rl->bf = EH;
		R_Rotate(&(*T)->rchild);
		L_Rotate(T);
	}
}




//構建二叉平衡樹函數
Status InsertAVL(BiTree* T, int e, Status* taller)
{
	if (!*T)
	{
		*T = (BiTree)malloc(sizeof(BiTNode));
		(*T)->data = e;
		(*T)->bf = EH;
		(*T)->lchild = (*T)->rchild = NULL;
		*taller = true;
	}
	else
	{
		if (e==(*T)->data)
		{
			*taller = false;
			return false;
		}
		if (e<(*T)->data)
		{
			int result = InsertAVL(&(*T)->lchild,e,taller);
			if (!result)
			{
				return false;
			}
			if (*taller)
			{
				switch ((*T)->bf)
				{
				case LH:
					LeftBalance(T);
					*taller = false;
					break;
				case EH:
					(*T)->bf = LH;
					*taller = true;
					break;
				case RH:
					(*T)->bf = EH;
					*taller = false;
					break;
				}
			}
		}
		else
		{
			int result = InsertAVL(&(*T)->rchild, e, taller);
			if (!result)
			{
				return false;
			}
			if (*taller)
			{
				switch ((*T)->bf)
				{
				case LH:
					(*T)->bf = EH;
					*taller = false;
					break;
				case EH:
					(*T)->bf = RH;
					*taller = true;
					break;
				case RH:
					RightBalance(T);
					*taller = false;
					break;
				}
			}
		}
	}
	return true;
}


//二叉樹中序遍歷遞歸算法
void InOrderTraverse(BiTree* T)
{
	if (*T==NULL)
	{
		return;
	}
	InOrderTraverse(&(*T)->lchild);
	cout << (*T)->data << " ";
	InOrderTraverse(&(*T)->rchild);
}

int main()
{
	int i;
	int a[10] = {3,2,1,4,5,6,7,10,9,8};
	BiTree T = NULL;
	Status Numtaller;
	for ( i = 0; i < 10; i++)
	{
		InsertAVL(&T,a[i],&Numtaller);
	}
	//中序遍歷輸出結果
	InOrderTraverse(&T);
}




本文參考網址:https://www.cnblogs.com/zuochengsi-9/p/8660871.html

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