求助AVL树……求后继WA了
查看原帖
求助AVL树……求后继WA了
316827
Temperature_automata楼主2021/2/4 22:37

代码:

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 1e5+5;
struct node {
  int l , r , val ; 
  int size ;
  int high ;
}avl[N] ;
int cnt , root , n ;

inline void newnode(int &now , int val) {
  avl[now==++cnt].val = val ;
  avl[cnt].size = 1 ;
  avl[cnt].high = 1 ;
}

inline void update(int now) {
  avl[now].size=avl[avl[now].l].size
  +avl[avl[now].r].size+1;
  avl[now].high = max(avl[avl[now].l].high
  ,avl[avl[now].r].high)+1;
}//更新

inline int factor ( int now ) {
  return avl[avl[now].l].high
  -avl[avl[now].r].high ;
}//求平衡因子:左子树高度-右子树高度

inline void left(int &now)//左旋拎右左挂右
{
  /*左旋->将右子树作为新根,根作为其左子树
  原右子树的左子树挂到原根的右边*/
  int r = avl[now].r ;//右子树
  avl[now].r = avl[r].l ;//左挂右
  avl[r].l = now ;
  now = r ;//拎右
  update(avl[now].l);
  update(now);
}

inline void right(int &now) {//右旋拎左右挂左
  /*右旋->将左子树作为新根,原根作为其右子树
  原左子树的右子树挂到原根的左边*/
  int l= avl[now].l ;//左子树
  avl[now].l = avl[l].r ;//右挂左
  avl[l].r = now ;
  now = l ;//拎左
  update(avl[now].r);
  update(now);
}

inline void check(int &now) {//检查是否平衡
  int now_factor = factor(now) ;
  if(now_factor>1)//左子树太高
  {
    int left_factor = factor(avl[now].l) ;
    if(left_factor>0) right(now) ;//LL
    else left(avl[now].l),right(now) ;//LR
  }
  else if(now_factor< -1) {
    int right_factor = factor(avl[now].r) ;
    if(right_factor<0) left(now) ;//RR
    else right(avl[now].r),left(now) ;//RL
  }
  else if(now)update(now) ;
  //如果平衡且非空,直接更新
}

void ins(int &now,int val) {
  if(!now)newnode(now,val) ;
  else if(val<avl[now].val) 
    ins(avl[now].l,val) ;
  else ins(avl[now].r,val) ;
  update(now) ;
  check(now) ;
}

int find_nxt ( int &now , int fa )
{
  int res ;
  if(!avl[now].l) {         //找到了后继
    res = now ;             //确定返回值
    avl[fa].l = avl[now].r ;
    //父亲的左儿改为该点的右儿
    update(now) ;
    update(fa) ;
  }
  else {                         //没找到
    res = find_nxt(avl[now].l,now) ;//接着找
    check(now) ;//检查
  }
  return res ;//返回结点编号
}//找某个点的后继

void del ( int &now , int val ) {
  if(val==avl[now].val) { //要删除的结点
    int l = avl[now].l ;
    int r = avl[now].r ;
    if(!l||!r) now = l + r ;
    //如果无儿或单儿,当前根节点替换
    else {//双儿
      now = find_nxt(r,r) ;   //找后继,替换当前
      if(now!=r) {        //如果后继不是原来的右儿
        avl[now].r = r ;  //右儿改为原来的右儿
      }
      avl[now].l = l ;    //连接左儿
    }
  }
  else if(val<avl[now].val) 
    del(avl[now].l,val) ;
  else del(avl[now].r,val) ;
  update(now) ;
  check(now) ;            //递归回溯检查
}

int getrank ( int val ) {
  int now = root , rank = 1 ;
  while(now) {
    if(val<=avl[now].val) {
      now = avl[now].l ;
    }
    else {
      rank += avl[avl[now].l].size + 1 ;
      now = avl[now].r ;
    }
  }
  return rank ;
}

int getnum(int rank) {
  int now = root ;
  while(now) {
    if(avl[avl[now].l].size+1==rank)
      break ;
    else if(avl[avl[now].l].size>=rank) {
      now = avl[now].l ;
    }
    else {
      rank -= avl[avl[now].l].size + 1 ;
      now = avl[now].r ;
    }
  }
  return avl[now].val ;
}

int main ( ) {
  cin >> n ;
  while(n--) {
    int opt , x ;
    cin >> opt >> x  ;
    switch(opt) {
      case 1 :
        ins(root,x) ;
        break ;
      case 2 :
        del(root,x) ;
        break ;
      case 3 :
        cout << getrank ( x ) << endl ;
        break ;
      case 4 :
        cout << getnum (x) << endl ; 
        break ;
      case 5 :
        cout << getnum(getrank(x)-1) << endl ;
        break ;
      case 6 :
        cout << getnum(getrank(x+1)) << endl  ;
        break ;
    }
  }
  system("pause") ;
  return 0 ;
}

2021/2/4 22:37
加载中...