1. 程式人生 > >平衡二叉樹(AVL樹)

平衡二叉樹(AVL樹)

一、平衡二叉樹的定義

平衡二叉樹是由前蘇聯兩位科學家G.M.Adelse-Velskil和E.M.Landis提出,因此一般也稱作AVL樹。AVL樹仍然是一顆二叉查詢樹,只是在其基礎上增加了“平衡”的要求。所謂平衡是指,對AVL樹的任意結點來說,其左子樹與右子樹的高度之差的絕對值不超過1;其中左子樹與右子樹的高度之差稱為該結點的平衡因子。 只要能隨時保證每個結點平衡因子的絕對值不超過1,AVL的高度就始終能保持O(logn)級別。由於需要對每個結點都得到平衡因子,因此需要在樹的結構中加入一個變數height,用來記錄以當前結點為根結點的子樹的高度:
struct node{
	int v, height;		//v為結點的權值,height為當前子樹高度 
	node *lchild, *rchild;	//左右孩子結點地址 
};

在這種定義下,如果需要新建一個結點,就可以採用如下寫法:
/**********生成一個新結點,v為結點權值**********/
node* newNode(int v){
	node* Node = new node;   //申請一個node型變數的地址空間 
	Node->v = v;         //結點權值為v 
	Node->height = 1;      //結點高度初始為1 
	Node->lchild = Node->rchild = NULL;    //初始狀態沒有左右孩子 
	return Node;   //返回新建結點的地址 
} 

可以通過下面的函式獲取結點root所在子樹的當前高度:
/******獲取以root為根結點的子樹的當前height*******/
int getHeight(node* root){
	if(root == NULL){
		return 0;        //空結點高度為0 
	}
	return root->height;
} 

於是根據定義,可以通過下面的函式計算平衡因子:
/*********計算結點root的平衡因子*********/ 
int getBanlanceFactor(node* root){
return getHeight(root->lchild) - getHeight(root->rchild);   //左子樹高度減右子樹高度 
}
結點root所在子樹的height等於其左子樹的height與右子樹的height的較大值加1,因此可以通過下面的函式來更新height:
/******更新結點root的height*******/ 
void updateHeight(node* root){
	root->height = max(getHeight(root->lchild), getHeight(root->rchild)) + 1;
}

二、平衡二叉樹的基本操作

1、查詢操作
/********search函式查詢AVL樹中資料域為x的結點*********/
void search(node* root, int x){
	if(root == NULL){                 //空樹,查詢失敗 
		printf("search failed\n");
		return;
	}
	if(x == root->data){        //查詢成功,訪問之 
		printf("%d\n", root->data); 
	}
	else if(x < root->data){     //如果x比根結點的資料域小,說明x在左子樹 
		search(root->lchild, x); //往左子樹搜尋x 
	}
	else{                        //如果x比根結點的資料域大,說明x在右子樹 
		search(root->rchild, x); //往右子樹上搜索x 
	}
}

2、插入操作
/************左旋(Left Rotation)************/ 
void L(node* &root){
	node* temp = root->rchild;     //root指向結點A,temp指向結點B 
	root->rchild = temp->lchild;   
	temp->lchild = root;         
	updateHeight(root);         //更新結點A的高度 
	updateHeight(temp);        //更新結點B的高度 
	root = temp;               
}

/***********右旋(Right Rotation)*************/ 
void R(node* &root){
	node* temp = root->lchild;    //root指向結點B,temp指向結點A 
	root->lchild = temp->rchild;
	temp->rchild = root;
	updateHeight(root);      //更新結點B的高度 
	updateHeight(temp);       //更新結點A的高度 
	root = temp;
} 

/**********插入權值為v的結點**********/
void insert(node* &root, int v){
	if(root == NULL){        //到達空結點 
		root = newNode(v);
		return;
	}
	if(v < root->v){     //v比根結點的權值小 
		insert(root->lchild, v);   //往左子樹插入
		updateHeight(root);       //更新樹高 
		if(getBalanceFactor(root) == 2){
			if(getBalanceFactor(root->lchild) == 1){    //LL型 
				R(root);
			}
			else if(getBalanceFactor(root->lchild) == -1){   //LR型 
				L(root->lchild);
				R(root);
			}
		} 
	}
	else{                //v比根結點的權值大 
		insert(root->rchild, v);     //往右子樹插入 
		updateHeight(root);             //更新樹高 
		if(getBalanceFactor(root) == -2){
			if(getBalanceFactor(root->rchild) == -1){      //RR型 
				L(root);
			}
			else if(getBalanceFactor(root->rchild) == 1){     //RL型 
				R(root->rchild);
				L(root);
			}
		}
	}
}

3、AVL樹的建立
/********AVL樹的建立*********/
node* create(int data[], int n){
	node* root = NULL;         //新建空根結點root
	for(int i = 0; i < n; i++){
		insert(root, data[i]);       //將data[0]~data[n-1]插入AVL樹中 
	} 
	return root;            //返回根結點 
}