平衡二叉树总结四:替罪羊树(scapegoat tree)

  之前在查treap树的时候,偶然在知乎看到一篇比treap树还简单的替罪羊树的介绍,传送门:https://zhuanlan.zhihu.com/p/21263304,大神还是写的很好的,有兴趣的可以去看下,当然也可以看我的总结。

一 、平衡条件

  左子树大小 < alpha * 根大小 并且 右子树大小 < alpha * 根大小

 二、 替罪羊树总结起来就两个操作:

  1.拉平,当树不满足平衡条件时,把树伸展成链表。

  2.重构,递归的选取链表的中点作为根节点重建平衡树,这样得到的几乎是完美的平衡二叉树。

三、基本操作

  0.结构

 

struct scapegoat{
  scapegoat* left;
  scapegoat* right;
  int val,size;
  bool real;
  scapegoat(int v,int s,bool r):val(v),size(s),real(r){left = right = NULL;}
};

  1.插入

  先正常的插入到二叉搜索树中,再回溯的过程中,判断是否违背了平衡条件,如果违背了,拉平并重构该树。

tree insert(tree t,int val){
  if(t==NULL){
    t = new scapegoat(val,1,1);
    return t;
  }
  bool r = 0;(t->size)++;
  if(val > t->val){
    t->right = insert(t->right,val);
    if(t->right->size > alpha*t->size+10){r=1;}
  }
  else if(val < t->val){
    t->left = insert(t->left,val);
    if(t->left->size > alpha*t->size+10){r=1;}
  }
  if(r){
    qu.clear();tree2list(t);
    t = rebuild(0,qu.size()-1);
  }
  return t;
}

  2.删除

  采用lazy删除,删除的给打上一个标记,每次重构都把lazy点删掉。

bool remove(tree t,int val){
  if(t==NULL)return 0;
  bool c;
  if(val>t->val)c = remove(t->right,val);
  else if(val<t->val)c = remove(t->left,val);
  else{
    if(t->real){t->real=0;c=1;}
    else{c=0;}
  }
  if(c)(t->size)--;
  return c;
}

3.总结

  总体来说思想很简单,不过编程还是有一定复杂度的,更treap树差不太多,性能的话据说是平均O(log(n))的,不过我的代码貌似重构的很频繁,不知道是不是写错了。

  现在研究的不深,之后有机会再补充。 

#include<iostream>
#include<vector>
#include<queue>
using namespace std;

struct scapegoat{
  scapegoat* left;
  scapegoat* right;
  int val,size;//值域与存储真实点个数的size域
  bool real;//该点是否是真实的
  scapegoat(int v,int s,bool r):val(v),size(s),real(r){left = right = NULL;}
}; 
typedef scapegoat* tree;
const int alpha = 0.55;//权重因子
vector<tree> qu;
void tree2list(tree t){//拉平树
  if(t==NULL)return;
  if(t->left)tree2list(t->left);
  if(t->real)qu.push_back(t);
  if(t->right)tree2list(t->right);
  if(!t->real)delete t;
}

tree rebuild(int left,int right){//重构树
  if(left > right)return NULL;
  int m = (left+right)/2;
  tree t = qu[m];
  t->size = right-left+1;
  t->left = rebuild(left,m-1);
  t->right = rebuild(m+1,right);
  return t;
}

tree insert(tree t,int val){
  if(t==NULL){
    t = new scapegoat(val,1,1);
    return t;
  }
  bool r = 0;(t->size)++;
  if(val > t->val){
    t->right = insert(t->right,val);
    if(t->right->size > alpha*t->size+10){r=1;}
  }
  else if(val < t->val){
    t->left = insert(t->left,val);
    if(t->left->size > alpha*t->size+10){r=1;}
  }
  if(r){
    cout << "dd" <<endl;
    qu.clear();tree2list(t);
    t = rebuild(0,qu.size()-1);
  }
  return t;
}

bool remove(tree t,int val){
  if(t==NULL)return 0;
  bool c;
  if(val>t->val)c = remove(t->right,val);
  else if(val<t->val)c = remove(t->left,val);
  else{
    if(t->real){t->real=0;c=1;}
    else{c=0;}
  }
  if(c)(t->size)--;
  return c;
}
void level(tree t){
  if(!t)return;
  tree now,last=t;
  queue<tree> qu1;
  qu1.push(t);
  while(qu1.size()){
    now = qu1.front();qu1.pop();
    if(now->left)qu1.push(now->left);
    if(now->right)qu1.push(now->right);
    cout << now->val << "(" << now->size << ")" << " ";
    if(now == last && qu1.size()){last = qu1.back();cout << endl;}
  }
  cout << endl;
}

int main(){
  int i;
  tree t=NULL;
  for(i=0;i<100;i++){
    t = insert(t,i);
  }
  level(t);
}

    原文作者:平衡二叉树
    原文地址: https://blog.csdn.net/tdscdma123/article/details/54093729
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞