AVL樹的旋轉、插入、刪除及遍歷C語言實現
阿新 • • 發佈:2018-12-30
一、AVL結構定義
struct AVLNode
{
int val;
struct AVLNode *left,*right;
int height;//AVL樹的高度
};
typedef struct AVLNode AVLNode;
注:在節點中新增高度標記的原因在於,在每次進行計算高度時,可以不必要遍歷訪問到根節點,而僅僅向子樹訪問一次即可,從o(logn)變為o(1),這樣可以提高效率。
注:高度改變的那些節點只可能是在第一次失衡節點向上到根中的路徑上的節點。
二、幾個函式
int Max(int a,int b){
return a>b?a:b;
}
int cptHeight(AVLNode *r){//計算樹高
return r?r->height:-1;
}
三、AVL的旋轉
AVLNode *lRotation(AVLNode *r)//左旋
{
AVLNode *p=r->right;
r->right=p->left;
p->left=r;
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
p->height=Max(cptHeight(p->left),cptHeight(p-> right))+1;
return p;
}
AVLNode *rRotation(AVLNode *r)//右旋
{
AVLNode *p=r->left;
r->left=p->right;
p->right=r;
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
p->height=Max(cptHeight(p->left),cptHeight(p->right))+1;
return p;
}
AVLNode * lrRotation(AVLNode *r)//lr旋轉
{
r->left=lRotation(r->left);
return rRotation(r);
}
AVLNode *rlRotation(AVLNode *r)//rl旋轉
{
r->right=rRotation(r->right);
return lRotation(r);
}
四、AVL的插入
avl在每次插入之後,可能會導致失衡,在失衡節點處,每次進行旋轉操作以保持其平衡性
AVLNode *AVLinsert(AVLNode *r,int e)
{
if(r==NULL){
r=(AVLNode*)malloc(sizeof(AVLNode));
r->val=e;
r->left=r->right=NULL;
r->height=0;//葉節點高度定義為0;
return r;
}
if(r->val<e){
r->right=AVLinsert(r->right,e);//在r右子樹中插入節點
if(cptHeight(r->right)-cptHeight(r->left)>=2){//插入節點後可能引起失衡
r=(cptHeight(r->right->left)>cptHeight(r->right->right))?rlRotation(r):lRotation(r);
//失衡節點r右子樹的左右高度不可能相同
//r右子樹左邊高度大於右邊,新插入節點在左邊,應進行rl旋轉,否則進行l旋轉
}
}
else if(r->val>e){
r->left=AVLinsert(r->left,e);//在r左子樹中插入節點
if(cptHeight(r->left)-cptHeight(r->right)>=2){//插入節點後可能引起失衡
r=(cptHeight(r->left->left)>cptHeight(r->left->right))?rRotation(r):lrRotation(r);
//失衡節點r左子樹的左右高度不可能相同
//左子樹左邊高度大於右邊,新插入節點在左邊,應進行r旋轉,否則進行lr旋轉
}
}
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
return r;
}
五、AVL的刪除
刪除節點時,與二叉搜尋樹一致,只是每次應該在刪除的路徑節點上,對相應失衡的節點進行旋轉操作
AVLNode *AVLremove(AVLNode *r,int e)
{
if(r==NULL) return r;
if(r->val<e){
r->right=AVLremove(r->right,e);
}
else if(r->val>e){
r->left=AVLremove(r->left,e);
}
else{//找到當前需要刪除的值
if(r->left&&r->right){//左右兒子都不為空
AVLNode *p=r->right;
while(p->left) p=p->left;//右邊子樹最小的值
r->val=p->val;
r->right=AVLremove(r->right,p->val);
}
else{
AVLNode *p=(r->left)?r->left:r->right;
free(r);
return p;
}
}
if(cptHeight(r->left)-cptHeight(r->right)>=2){//對右邊節點進行刪除引起失衡
r=(cptHeight(r->left->left)>cptHeight(r->left->right))?rRotation(r):lrRotation(r);
//注意,此時失衡節點r左子樹左右高度可能相等,相等時,採取不同的旋轉策略將得到不同的AVL樹
}else if(cptHeight(r->right)-cptHeight(r->left)>=2){//對左邊節點進行刪除引起失衡
r=(cptHeight(r->right->left)>cptHeight(r->right->right))?rlRotation(r):lRotation(r);
//同上
}
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
//更新相應的節點高度值
return r;
}
六、完整測試程式碼
#include <stdio.h>
#include <malloc.h>
struct AVLNode
{
int val;
struct AVLNode *left,*right;
int height;//AVL樹的高度
};
typedef struct AVLNode AVLNode;
int Max(int a,int b){
return a>b?a:b;
}
int cptHeight(AVLNode *r){
return r?r->height:-1;
}
AVLNode *lRotation(AVLNode *r)
{
AVLNode *p=r->right;
r->right=p->left;
p->left=r;
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
p->height=Max(cptHeight(p->left),cptHeight(p->right))+1;
return p;
}
AVLNode *rRotation(AVLNode *r)
{
AVLNode *p=r->left;
r->left=p->right;
p->right=r;
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
p->height=Max(cptHeight(p->left),cptHeight(p->right))+1;
return p;
}
AVLNode *lrRotation(AVLNode *r)
{
r->left=lRotation(r->left);
return rRotation(r);
}
AVLNode *rlRotation(AVLNode *r)
{
r->right=rRotation(r->right);
return lRotation(r);
}
AVLNode *AVLinsert(AVLNode *r,int e)
{
if(r==NULL){
r=(AVLNode*)malloc(sizeof(AVLNode));
r->val=e;
r->left=r->right=NULL;
r->height=0;//葉節點高度定義為0;
return r;
}
if(r->val<e){
r->right=AVLinsert(r->right,e);//在r右子樹中插入節點
if(cptHeight(r->right)-cptHeight(r->left)>=2){//插入節點後可能引起失衡
r=(cptHeight(r->right->left)>cptHeight(r->right->right))?rlRotation(r):lRotation(r);
//失衡節點r右子樹的左右高度不可能相同
//r右子樹左邊高度大於右邊,新插入節點在左邊,應進行rl旋轉,否則進行l旋轉
}
}
else if(r->val>e){
r->left=AVLinsert(r->left,e);//在r左子樹中插入節點
if(cptHeight(r->left)-cptHeight(r->right)>=2){//插入節點後可能引起失衡
r=(cptHeight(r->left->left)>cptHeight(r->left->right))?rRotation(r):lrRotation(r);
//失衡節點r左子樹的左右高度不可能相同
//左子樹左邊高度大於右邊,新插入節點在左邊,應進行r旋轉,否則進行lr旋轉
}
}
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
return r;
}
AVLNode *AVLremove(AVLNode *r,int e)
{
if(r==NULL) return r;
if(r->val<e){
r->right=AVLremove(r->right,e);
}
else if(r->val>e){
r->left=AVLremove(r->left,e);
}
else{//找到當前需要刪除的值
if(r->left&&r->right){//左右兒子都不為空
AVLNode *p=r->right;
while(p->left) p=p->left;//右邊子樹最小的值
r->val=p->val;
r->right=AVLremove(r->right,p->val);
}
else{
AVLNode *p=(r->left)?r->left:r->right;
free(r);
return p;
}
}
if(cptHeight(r->left)-cptHeight(r->right)>=2){//對右邊節點進行刪除引起失衡
r=(cptHeight(r->left->left)>cptHeight(r->left->right))?rRotation(r):lrRotation(r);
//注意,此時失衡節點r左子樹左右高度可能相等,相等時,採取不同的旋轉策略將得到不同的AVL樹
}else if(cptHeight(r->right)-cptHeight(r->left)>=2){//對左邊節點進行刪除引起失衡
r=(cptHeight(r->right->left)>cptHeight(r->right->right))?rlRotation(r):lRotation(r);
//同上
}
r->height=Max(cptHeight(r->left),cptHeight(r->right))+1;
//更新相應的節點高度值
return r;
}
void pretra(AVLNode *r)//前序
{
if(r){
printf("<%d, %d> ",r->val,r->height);
pretra(r->left);
pretra(r->right);
}
}
void inotra(AVLNode *r)//中序
{
if(r){
inotra(r->left);
printf("<%d, %d> ",r->val,r->height);
inotra(r->right);
}
}
void tra(AVLNode *r){
printf("pretra: ");
pretra(r);
printf("\n");
printf("inotra: ");
inotra(r);
printf("\n");
}
int main()
{
char op;
int e;
AVLNode *r=NULL;
while(scanf("%c %d",&op,&e))
{
switch(op){
case 'i':r=AVLinsert(r,e),tra(r);break;//插入e
case 'r':r=AVLremove(r,e),tra(r);break;//刪除e
default:printf("error\n");break;
}
getchar();
}
return 0;
}