平衡二叉树-替罪羊树 c/c++代码实现

参考:https://www.bilibili.com/video/BV1Wt411L7te?t=1822大佬视频
需要重构的条件是:当前结点的左子树或右子树的大小大于当前结点的大小乘一个平衡因子alpha或者以当前节点为根的子树内被删除的结点数量大于树大小的30%了
代码中有比较详细的注释

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 2e5+10;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 100000000;
using namespace std;
struct Node{
    int l,r,val;
    int size,fact;
    bool exist;
}node[maxn];
int root,cnt;
vector<int> v;
void creat(int &now,int val){   //创建一个新结点
    now=++cnt;
    node[now].val=val;  //值等于val
    node[now].size=node[now].fact=1;    //实际结点大小=节点大小
    node[now].exist=true; //结点是否存在
}
/*需要重构的条件是:当前结点的左子树或右子树的大小大于当前结点的大小乘一个平衡因子alpha或者以当前节点为根的子树内被删除的结点数量大于树大小的30%了*/
bool imbalence(int now){   //判断是否需要重构
    if((max(node[node[now].l].size,node[node[now].r].size)>node[now].size*0.75)
       ||(node[now].size-node[now].fact>node[now].size*0.3))
        return true;
    return false;
}
void ldr(int now){   //中序遍历暴力重构
    if(!now) return;
    ldr(node[now].l);
    if(node[now].exist) v.push_back(now);
    ldr(node[now].r);
}
void lift(int l,int r,int &now){   //将中序遍历的vector进行重构(分治的方法完成)
    if(l==r){    //分治到只有一个结点
        now=v[l];
        node[now].l=node[now].r=0;
        node[now].size=node[now].fact=1;
        return;
    }
    int mid=(l+r)/2; //取最中间的结点(为了让生成的树尽量平衡)
    while (l<mid&&node[v[mid]].val==node[v[mid-1]].val) mid--;   //这里比较重要
    now=v[mid];   /* 我们平衡二叉树的定义是,如果一个数大于或等于当前节点,我们要把它往右边放置,所以如果中间左边的结点跟我们中间取得结点相同,那我们就应该取左边的那个结点作为根节点*/
    if(l<mid) lift(l,mid-1,node[now].l);
    else node[now].l=0;
    lift(mid+1,r,node[now].r);
    node[now].size=node[node[now].l].size+node[node[now].r].size+1;  //回溯方法更新结点的实际大小和大小
    node[now].fact=node[node[now].l].fact+node[node[now].r].fact+1;
}

void rebuild(int &now){   //重构函数
    v.clear();
    ldr(now);
    if(v.empty()){
        now=0;
        return;
    }
    lift(0,v.size()-1,now);
}

void update(int now,int end){   //更新结点
    if(!now) return;
    if(node[end].val<node[now].val) update(node[now].l,end);
    else update(node[now].r,end);
    node[now].size=node[node[now].l].size+node[node[now].r].size+1;
}

void check(int &now,int end){  //检查树是否符合条件
    if(now==end) return;
    if(imbalence(now)){
        rebuild(now);
        update(root,now);
        return;
    }
    if(node[end].val<node[now].val) check(node[now].l,end);
    else check(node[now].r,end);
}

void insert(int &now,int val){  //插入一个数
    if(!now){
        creat(now,val);  //插入后判断是否符合标准
        check(root,now);
        return;
    }
    node[now].size++;  //回溯更新结点大小和实际大小
    node[now].fact++;
    if(val<node[now].val)  insert(node[now].l,val);
    else  insert(node[now].r,val);
}
void del(int now,int val){   //删除结点,首先要判断结点是否存在,不存在就没有删除的必要了
    if(node[now].exist&&val==node[now].val){
        node[now].exist=false;
        node[now].fact--;
        check(root,now);
        return;
    }
    node[now].fact--;
    if(val<node[now].val) del(node[now].l,val);
    else del(node[now].r,val);
}
int get_rank(int val){   //得到名次
    int now=root,rank=1;  //名次等于所有比他小的数+1,也就是说如果有多个相同的数,排名是第一个数的名次
    while (now){
        if(val<=node[now].val) now=node[now].l;  //如果当前值比节点值小,往左递归
        else{
            rank+=node[now].exist+node[node[now].l].fact;  //如果大于当前结点,就需要加上比他小的结点在加上这个根节点(如果根节点存在的话)
            now=node[now].r;  //往右子树寻找
        }
    }
    return rank;
}
int get_num(int rank){    //给定排名求字母
    int now=root;
    while (now){
        if(node[now].exist&&node[node[now].l].fact+node[now].exist==rank) break;  //如果找到排名,直接返回排名
        else if(node[node[now].l].fact>=rank) now=node[now].l; //没找到就继续向下寻找
        else{
            rank-=node[node[now].l].fact+node[now].exist;  //如果往右子树找,相当于这个数比左边的数都打,所以排名要减去左边的大小
            now=node[now].r;
        }
    }
    return node[now].val;
}
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        int ch,x;
        scanf("%d%d",&ch,&x);
        if(ch==1) insert(root,x);
        if(ch==2) del(root,x);
        if(ch==3) printf("%d\n",get_rank(x));
        if(ch==4) printf("%d\n",get_num(x));
        if(ch==5) printf("%d\n",get_num(get_rank(x)-1));
        if(ch==6) printf("%d\n",get_num(get_rank(x+1)));
//        v.clear();
//        ldr(root);
//        for(auto it : v) printf("%d ",node[it].val);
//        cout<<endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
平衡二叉树(AVL)是一种自平衡的二叉搜索,它的左子和右子的高度差不超过1。下面是一个简单的平衡二叉树代码实现(C语言): ```c #include <stdio.h> #include <stdlib.h> // 定义平衡二叉树节点结构 typedef struct AVLNode { int data; // 节点数据 int height; // 节点高度 struct AVLNode* left; // 左子指针 struct AVLNode* right; // 右子指针 } AVLNode; // 获取节点的高度 int getHeight(AVLNode* node) { if (node == NULL) { return 0; } return node->height; } // 计算节点的平衡因子 int getBalanceFactor(AVLNode* node) { if (node == NULL) { return 0; } return getHeight(node->left) - getHeight(node->right); } // 更新节点的高度 void updateHeight(AVLNode* node) { int leftHeight = getHeight(node->left); int rightHeight = getHeight(node->right); node->height = (leftHeight > rightHeight ? leftHeight : rightHeight) + 1; } // 左旋操作 AVLNode* leftRotate(AVLNode* node) { AVLNode* newRoot = node->right; node->right = newRoot->left; newRoot->left = node; updateHeight(node); updateHeight(newRoot); return newRoot; } // 右旋操作 AVLNode* rightRotate(AVLNode* node) { AVLNode* newRoot = node->left; node->left = newRoot->right; newRoot->right = node; updateHeight(node); updateHeight(newRoot); return newRoot; } // 插入节点 AVLNode* insertNode(AVLNode* root, int data) { if (root == NULL) { AVLNode* newNode = (AVLNode*)malloc(sizeof(AVLNode)); newNode->data = data; newNode->height = 1; newNode->left = NULL; newNode->right = NULL; return newNode; } if (data < root->data) { root->left = insertNode(root->left, data); } else if (data > root->data) { root->right = insertNode(root->right, data); } else { // 已存在相同节点,不进行插入 return root; } updateHeight(root); int balanceFactor = getBalanceFactor(root); // 左子高度大于右子 if (balanceFactor > 1) { if (data < root->left->data) { // 左左情况,进行右旋操作 return rightRotate(root); } else if (data > root->left->data) { // 左右情况,先对左子进行左旋操作,再对根节点进行右旋操作 root->left = leftRotate(root->left); return rightRotate(root); } } // 右子高度大于左子 if (balanceFactor < -1) { if (data > root->right->data) { // 右右情况,进行左旋操作 return leftRotate(root); } else if (data < root->right->data) { // 右左情况,先对右子进行右旋操作,再对根节点进行左旋操作 root->right = rightRotate(root->right); return leftRotate(root); } } return root; } // 中序遍历二叉树 void inorderTraversal(AVLNode* root) { if (root == NULL) { return; } inorderTraversal(root->left); printf("%d ", root->data); inorderTraversal(root->right); } int main() { AVLNode* root = NULL; int data[] = {5, 3, 7, 2, 4, 6, 8}; int n = sizeof(data) / sizeof(data); for (int i = 0; i < n; i++) { root = insertNode(root, data[i]); } printf("中序遍历结果:"); inorderTraversal(root); printf("\n"); return 0; } ``` 这段代码实现平衡二叉树的插入操作,并提供了一个简单的示例来演示插入操作后的中序遍历结果。你可以根据需要修改代码来适应其他操作,比如删除节点等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值