AVL树通过旋转操作来维持其“平衡”,即尽可能接近满二叉树的形状,这样才能在查找等操作时发挥树结构的优势,达到log(n)的速度,否则一个退化的二叉树就成链表了。
AVL树的旋转操作不难理解,找个带插图的文章看看就很容易明白,不过实现起来就比较麻烦,主要在于情况分类比较多,一会这个节点要认爹一会那个节点要换儿子,最好能自己在纸上把所有情况画一画。
#include <iostream>
#include<windows.h>
#define MAX 100
using namespace std;
struct node{
int n;
int b;
node *l,*r;
node(int nn){
n=nn; b=0;
l=r=NULL;
}
};
struct btree{
node *root;
node *sta[MAX];
int top;
btree(){
root=NULL;
}
void single(node *F,node *A,node *B,int flag){ // flag=1,右旋; 0左旋
node **bch; bch=flag? &(B->r) : &(B->l);
node **ach; ach=flag? &(A->l) : &(A->r);
*ach=*bch;
*bch=A;
if(F!=NULL){
if(F->l==A) F->l=B;
else F->r=B;
}
else root=B;
}
void revolve(node *B,node *A){
node *F=sta[top];
int flag= A->b > 0 ? 1:0;
node *C=flag?B->r:B->l;
if(A->b*B->b>0){
single(F,A,B,flag);
A->b=0; B->b=0;
}
else{
single(A,B,C,1-flag);
single(F,A,C,flag);
if(A->b*C->b>0){
B->b=0; A->b=-C->b;
}
else{
A->b=0; B->b=-C->b;
}
C->b=0;
}
}
void checkbalance(node *p){
node *q;
while(q=sta[top--]){
if(p==q->l) q->b++;
else q->b--;
if(q->b==0) break;
if(q->b==2||q->b==-2){
revolve(p,q);
break;
}
p=q;
}
}
void insert(int n){
node **p=&root;
top=0; sta[top]=NULL;
while((*p)){
sta[++top]=*p;
if( n < (*p)->n ) p=&((*p)->l);
else p=&((*p)->r);
}
*p=new node(n);
checkbalance(*p);
}
bool creat(){
int n;
cout<<"请输入若干数据,以Ctrl+Z结束\n";
cout<<"(直接输入Ctrl+Z退出程序)\n";
while(cin>>n) insert(n);
cin.clear();
if(root==NULL) return 1;
else return 0;
}
bool srch(int n){
node *p=root;
while(p){
if(p->n==n) return 1;
else if(p->n<n) p=p->r;
else p=p->l;
}
return 0;
}
};
int main(){
while(1){
btree t;
if(t.creat()) break;
while(1){
cout<<"请选择功能, 1.查找; 2.插入新元素; 3.重建一个树: ";
int sel,n;
cin>>sel;
if(sel==1){
cout<<"请输入要查找的值: ";
cin>>n;
if(t.srch(n)) cout<<" 查找成功!\n";
else cout<<" 查找失败!\n";
}
else if(sel==2){
cout<<"请输入要插入的值: ";
cin>>n;
t.insert(n);
cout<<" 插入成功!\n";
}
else{
system("cls");
break;
}
}
}
return 0;
}