本文转自 http://www.asiteof.me/2010/06/avl/
用到的树的节点如下所示:
struct node{ int data; int bf; node *lchild; node *rchild; };
其中data表示该节点存储数据,bf表示当前节点的高度,lchild指向当前节点的左儿子,rchild指向当前节点的右儿子。
对于二叉树的建立与节点的插入在本次实验中采用递归的方法,首先找到插入节点,然后递归的判断,如果节点左儿子与右儿子的高度差大于等于2,则对该节点进行平衡调整。
对于二叉树的删除操作,先递归的搜索要删除的节点A,用该节点的右儿子的最左儿子B代替该节点,以A的右儿子和B当前的数值作为线索继续遍历,只到找到B,删除B。然后递归的对B的祖先节点进行平衡调整,具体调整操作和二叉树的插入操作的平衡调整相同。
对二叉树的平衡调整过程,主要包含四种旋转操作:LL,LR,RR,RL。
LR由当前节点左儿子的一次RR旋转和当前节点的一次LL旋转构成。同理, RR由当前节点右儿子的一次LL旋转和当前节点的一次RR旋转构成。
以下为源代码:
#include <stdio .h> #include <stdbool .h> #include <stdlib .h> char chos; int input; bool unbalanced = false; struct node{ int data; int bf; node *lchild; node *rchild; }; typedef struct node *BST; BST R = NULL; void Chose(){ printf("i) Insert a point\n" "d) Delete a point\n" "e) exit\n" "Input your choose:"); scanf(" %c", &chos); } int Height(BST T){ /*返回当前节点的高度*/ if(T == NULL) return -1; else return T->bf; } int Max(int A, int B){ return ((A > B) ? A:B); } BST SingleRotateWithRight(BST K2){ /*RR型旋转*/ BST K1; K1 = K2->rchild; K2->rchild = K1->lchild; K1->lchild = K2; K2->bf = Max(Height(K2->lchild), Height(K2->rchild)) + 1; K1->bf = Max(Height(K1->lchild), Height(K1->rchild)) + 1; return K1; } BST SingleRotateWithLeft(BST K2){ /*LL型旋转*/ BST K1; K1 = K2->lchild; K2->lchild = K1->rchild; K1->rchild = K2; K2->bf = Max(Height(K2->lchild), Height(K2->rchild)) + 1; K1->bf = Max(Height(K1->lchild), Height(K1->rchild)) + 1; return K1; } BST DoubleRotateWithLeft(BST K3){ /*LR = RR(K3->lchild) + LL(K3)*/ K3->lchild = SingleRotateWithRight(K3->lchild); return SingleRotateWithLeft(K3); } BST DoubleRotateWithRight(BST K3){ /*LL = LL(K3->lchild) + RR(K3)*/ K3->rchild = SingleRotateWithLeft(K3->rchild); return SingleRotateWithRight(K3); } void OUT(BST T){ /*树的输出递归函数*/ if(T->lchild){ printf("Left\t%d\t[parent:%d]\n", T->lchild->data, T->data); OUT(T->lchild); } if(T->rchild){ printf("Right\t%d\t[parent:%d]\n", T->rchild->data, T->data); OUT(T->rchild); } } BST Rotate(BST T){ /*对于单个节点进行的AVL调整*/ if(Height(T->lchild) - Height(T->rchild) == 2){ if(Height(T->lchild->lchild) >= Height(T->lchild->rchild)){ T = SingleRotateWithLeft(T); } else{ T = DoubleRotateWithLeft(T); } } if(Height(T->rchild) - Height(T->lchild) ==2){ if(Height(T->rchild->rchild) >= Height(T->rchild->lchild)){ T = SingleRotateWithRight(T); } else{ T = DoubleRotateWithRight(T); } } return T; } BST AVLInsert(BST T){ /*AVL数的插入操作*/ if(T == NULL){ T = (BST)malloc(sizeof(struct node)); T->data = input; T->lchild = T->rchild = NULL; T->bf = 0; } else if(input < T->data){ T->lchild = AVLInsert(T->lchild); if(Height(T->lchild) - Height(T->rchild) == 2){ if(input < T->lchild->data){ T = SingleRotateWithLeft(T); /*LL旋转*/ } else{ T = DoubleRotateWithLeft(T); /*LR旋转*/ } } } else if(input > T->data){ T->rchild = AVLInsert(T->rchild); if(Height(T->rchild) - Height(T->lchild) == 2){ if(input > T->rchild->data){ T = SingleRotateWithRight(T); /*RR旋转*/ } else{ T = DoubleRotateWithRight(T); /*RL旋转*/ } } } T->bf = Max(Height(T->lchild), Height(T->rchild)) + 1; return T; } void Output(BST T){ if(T == NULL){ printf("None\n"); } else{ printf("%d\troot\n", T->data); OUT(T); } } void Insert(){ printf("\nInput the point your want to Insert: "); scanf("%d", &input); R = AVLInsert(R); Output(R); } BST AVLDelete(BST T, int key){ if(T == NULL) return NULL; if(key == T->data){ if(T->rchild == NULL){ /*如果T得右儿子为空则直接删除*/ BST temp = T; T = T->lchild; free(temp); } else{ /*否则找到T->rchild的最左儿子代替T*/ BST temp = T->rchild; while(temp->lchild != NULL){ temp = temp->lchild; } T->data = temp->data; T->rchild = AVLDelete(T->rchild, temp->data); /*对于替代后的T及其各个子节点进行一些列调整,正到再次递归到T->rchild的最左儿子,删除它*/ T->bf = Max(Height(T->lchild), Height(T->rchild)) + 1; } return T; } else if(key < T->data){ T->lchild = AVLDelete(T->lchild, key); } else{ T->rchild = AVLDelete(T->rchild, key); } T->bf = Max(Height(T->lchild), Height(T->rchild)) + 1; if(T->lchild != NULL){ T->lchild = Rotate(T->lchild); } if(T->rchild != NULL){ T->rchild = Rotate(T->rchild); } T = Rotate(T); return T; } void Delete(){ printf("\nInput the point you want to Delete: "); scanf("%d", &input); R = AVLDelete(R, input); Output(R); } int main(){ while(1){ Chose(); switch(chos){ case 'i': Insert(); break; case 'd': Delete(); break; case 'e': exit(0); } } return 0; }
以上代码为c++实现,但经过修改,完全可以修改为java的版本。在整个实现过程当中,添加的操作稍微简单一些,在删除节点上要考虑单个树的翻转操作。删除可以考虑为添加和逆运算,但如何逆运算则需要仔细地去处理,本文在实现上有了一个参考,接下来就可以修改为java的实现版本了。
转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/201109040001.html
删除操作貌似错了,考虑要删除的是根,树高度为2,右子树只有一个结点,你的函数并没有完成删除操作,第一个return 前面应该包含平衡调整操作