AVLツリーメモ(二):mantain、delete
5247 ワード
まずmantainで操作します.AVLTREのバランスを維持できます.mantainがあったら、AVLTREのinsertとdeleteはすぐにバランスを維持するのではなく、操作が終わったらバランスを維持することができます.
void maintain(int &r)
{
if(tree[tree[r].lc].h==tree[tree[r].rc].h+2)
{
int t=tree[r].lc;
if(tree[tree[t].lc].h==tree[tree[r].rc].h+1)r=zig(r);
else if(tree[tree[t].rc].h==tree[tree[r].rc].h+1)r=zagzig(r);
}
else if(tree[tree[r].rc].h==tree[tree[r].lc].h+2)
{
int t=tree[r].rc;
if(tree[tree[t].rc].h==tree[tree[r].lc].h+1)r=zag(r);
else if(tree[tree[t].lc].h==tree[tree[r].lc].h+1)r=zigzag(r);
}
tree[r].h=max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1;
}
よく見ると昨日のinsertのメンテナンスバランスと似ています.今回はtree[r].vと挿入値xでxを比較することができません.左子樹か右子樹かをhで判断します.そしてinsertは二叉で木を探すinsertです.int insert(int r,int x)
{
if(r==0)
{
tree[++cnt].v=x;
tree[cnt].h=1;
return cnt;
}
if(tree[r].v>x)tree[r].lc=insert(tree[r].lc,x);
else if(tree[r].v<x)tree[r].rc=insert(tree[r].rc,x);
maintain(r);
return r;
}
次はdelete操作です.まず私達はfind、findが来たらdeleteにします.deleteのポイントは葉なら、直接削除します.息子が一人しかいないなら、この点を削除して、その父親を直接に息子につなげます.息子が左右にいるなら、面倒です.その前駆を見つけて、この点の値を前駆の値に修正して、最後に前駆を削除します.前駆は必ず息子が2人いるという状況がないことが証明されています.可能なのはこの点を削除すると、前駆者が上に来るからです.この点を直接前駆に変えて、前の駆を削除したほうがいいです.実際の実装はfindを参照することができる.findが来たら、前の2つの状況なら、削除します.第三種類なら、現在のポイントの前駆を削除します.削除したらh値を維持してください.int del(int &r,int x)
{
int tv;
if(x==tree[r].v||(x<tree[r].v&&tree[r].lc==0)||(x>tree[r].v&&tree[r].rc==0))
{
if(tree[r].lc==0||tree[r].rc==0)
{
tv=tree[r].v;
r=tree[r].lc+tree[r].rc;
return tv;
}
else tree[r].v=del(tree[r].lc,x);
}
else
{
if(tree[r].v>x)tv=del(tree[r].lc,x);
else tv=del(tree[r].rc,x);
}
maintain(r);
return tv;
}
求前駆の関数を直接呼び出さないでください.時間の複雑さが大きくなります.