登峰造极之树——平衡树

在所有的平衡树中,为陈启峰提出的SBT最富盛名,并且最快最方便。

下面就是我对此的学习过程。

首先要了解二叉排序树,然后要明白了旋转在平衡过程中的重要地位。

有左旋和右旋之分,下面以右旋为例,左旋对称即可:




于是我们可以很清楚的得到右旋代码:

void RR(int &t){
	int k=left[t];
	left[t]=right[k];
	right[k]=t;
	s[k]=s[t];
	s[t]=s[left[t]]+s[right[t]]+1;
	t=k;
}
相对应的就有了左旋的:

void LR(int &t){
	int k=right[t];
	right[t]=left[k];
	left[k]=t;
	s[k]=s[t];
	s[t]=s[left[t]]+s[right[t]]+1;
	t=k;
}


接下来就是SBT最重要的过程:Maintain(维护)

给出性质a:s[right[t]]>=s[left[left[t]]],s[right[left[t]]]

     性质b:s[left[t]]>=s[right[right[t]]],s[left[right[t]]]

说白了就是深度浅的结点数一定要大于深度深的,不然树就有所偏向了。

而maintain过程就是针对于插入过程中破环了这两个性质,我认为这个可以背出来,

举个例子加深理解:

 插入到左子树的左儿子中,导致左子树结点数多了,就右旋,变到左边来;

 插入到左子树的右儿子中,应先用左旋把最底下的儿子调上来,再整个右旋;

最后整个维护:

void maintain(int &t,bool flag){   //flag是指目前是插入了哪边的子树
	if (!flag)
		if (s[left[left[t]]]>s[right[t]])RR(t);
			else
				if (s[right[left[t]]]>s[right[t]]){
					LR(left[t]);
					RR(t);
				}
				else return ;
	else
		if (s[left[right[t]]] > s[left[t]])LR(t);
			else 
				if (s[right[right[t]]]>s[left[t]]){
					RR(right[t]);
					LR(t);
				}
	            else return ;
	maintain(left[t],false);
	maintain(right[t],true);//只需维护左假右真,对于左真右假在下面的两次调用中体现了,无需单独维护,证明略
	maintain(t,true);
	maintain(t,false);
}

于是,我们就可以很简单的写出对应的插入和删除过程:

void insert(int &t,int v){
	if (t==0){
		t=++cnt;
		left[cnt]=0;
		right[cnt]=0;
		s[cnt]=1;
		key[cnt]=v;
		return;
	}
	s[t]++;
	if (v<key[t])insert(left[t],v);
		else insert(right[t],v);
	maintain(t,v>=key[t]);
}
int Delete(int &t,int v){
	s[t]--;
	int Del;
	if (v==key[t] || (v<key[t] && left[t]==0) || (v>key[t] && right[t]==0)){
		Del=key[t];
		if (left[t]==0 || right[t]==0)t=left[t]+right[t];
			else key[t]=Delete(left[t],key[t]+1);
		return Del;
	}
	if (v<key[t])Del=Delete(left[t],v);
		else Del=Delete(right[t],v);
	return Del;
}

至此,SBT就结束了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值