为什么现在AVL树都是利用一些高端的node类而不是利用数组来维护二叉树结点属性
像我这语言不精的人就看不懂,并且代码量都偏大。
二叉树中,left和right属性都是比较对称的,为什么不利用它将代码精简?
比如说AVL树的Balance:
bool Balance(int x,bool y){
if(h[son[x][y]]>h[son[x][!y]]+1){
if(h[son[son[x][y]][y]]<h[son[son[x][y]][!y]])
Rotate(son[x][y],y);
Rotate(x,!y);
return 1;
}
return 0;
}
只有9行,合并了旋转(Rotate(int x,bool y))
合并了两种不平衡情况,并且为什么要是 bool 型,这在Insert中会有交代。
注:y==0时表明左子树高
y==1时表明右子树高。
合并后的Rotate(int x,bool y):
void Rotate(int x,bool t){ int y=son[x][!t]; son[x][!t]=son[y][t]; if(son[y][t]) pre[son[y][t]]=x; pre[y]=pre[x]; if(pre[x]==0) root=y; else{ son[pre[x]][x==son[pre[x]][1]]=y; } son[y][t]=x; pre[x]=y; h[x]=max(h[son[x][0]],h[son[x][1]])+1; h[y]=h[x]+1; }
//此外我想问一下,为什么代码字体颜色变了
这里将CLRS中的两个Rotate()合为了一个。
注:y==0时是左旋,右子树较高。
y==1时是右旋,左子树较高。
Insert函数:
void Insert(int t,int value){
int y=root,x=0;
T[t]=value;
if(y==0)
root=t;
else{
while(y){
x=y;
y=son[y][T[y]<value];
}
son[x][T[x]<value]=t;
}
pre[t]=x;
h[t]=1;
son[t][0]=0,son[t][1]=0;
while(x){
y=h[x];
h[x]=max(h[son[x][0]],h[son[x][1]])+1;
if(h[x]==y||Balance(x,T[x]<value))
break;
x=pre[x];
}
}
仍然抄的CLRS中的Insert。
但你可能会怀疑
if(h[x]==y||Balance(x,T[x]<value))
break;
为什么要break;
因为当 当前要平衡的树高度不变时,那么其父结点及以上的结点都还是平衡的;
而若该结点进行了Balance,那么它的高度一定不变(但它没怎么节省时间,我只是为了节约行数);
你可以改成:
if(h[x]==y)
break;
Balance(x,T[x]<value);
这下有三行了。
而令人心疼的是Delete()
既不能简化又不能中途break;
Delete:
void Transplant(int x,int y){ if(pre[x]==0) root=y; else{ son[pre[x]][x==son[pre[x]][1]]=y; } if(y) pre[y]=pre[x]; } int maximum(int x){ while(son[x][1]) x=son[x][1]; return x; } void Delete(int x){ int y=son[x][0],z=pre[x],v=0; if(y==0){ v=son[x][1]; Transplant(x,son[x][1]); } else{ if(son[x][1]==0){ v=son[x][0]; Transplant(x,son[x][0]); } else{ y=maximum(y); z=pre[y]; if(z!=x){ v=son[y][0]; Transplant(y,son[y][0]); son[y][0]=son[x][0]; pre[son[y][0]]=y; } else{ v=y; } Transplant(x,y); son[y][1]=son[x][1]; pre[son[y][1]]=y; } } while(z){ h[z]=max(h[son[z][0]],h[son[z][1]])+1; Balance(z,son[z][0]==v); v=z; z=pre[z]; } }
CLRS上的Delete简化不了;
但Search稍稍简化了;
Search:
int search(int value){
int x=root;
while(x){
if(T[x]==value)
return x;
x=son[x][T[x]<value];
}
return 0;
}
代码共计106行。此外,T.nil=0,即哨兵为0;
给出10000000=10^7个随机数据插入到AVL树中用时:
15804ms
16002ms
15804ms
16秒
h=27
都是一组数据;
而直接插入二叉树中用时:AVL树的简单,数组写法
188473ms
186718ms
186191ms
三分钟……