红黑树 Red Black Tree及有关知识点

提到这个就是我的痛啊,不说了...学!

目录

二叉查找树

基本操作

平衡二叉树AVL

基本操作


首先复习一下平衡二叉树AVL,这就不得不先复习二叉查找树BST  


二叉查找树

递归定义:

① 要么为空树;

② 要么又根节点、左右子树构成,其中左右子树都为二叉查找树,其中右子树的数据域均大于根节点的数据域,左子树的数据域均小于根节点的数据域。

基本操作

查找

思路:

① 若当前节点root为空,则说明查找失败,不存在该数的节点;

② 若当前节点root->val等于查询的值,则说明查找成功;

③ 若当前节点root->val大于查询的值,root=root->left,继续递归;

④ 若当前节点root->val小于查询的值,root=root->right,继续递归。

void search(node* root, int x){
    if(root==NULL){
        cout<<"search failed."<<endl;
        return;
    }
    if(x==root->val){
        cout<<"search succeed."<<endl;
    }
    else if(x>root->val){
        search(root->right,x);
    }
    else{
        search(root->left,x);
    }
}

插入

思路:

给定根节点root和需要插入的值,若root==NULL,则说明为空树,新建节点作为根节点;否则,则按照查找的步骤进行,若查找成功,则说明不需要再进行插入,该值存在于树中;若查找失败,则在该root处进行插入新节点。

void insert(node* &root, int x){
    if(root==NULL){
        root = newNode(x);        //此处newNode为自建的新建节点API
        return;
    }
    if(x==root->val){
        cout<<"该值已经存在."<<endl;
        return;
    }
    else if{x>root->val}{
        insert(root->left,x);
    }
    else{
        insert(root->right,x);
    }
}

建树

本质就是重复调用insert函数进行插入

node* create(int* data,int n){
    node* root = NULL;
    for(int i=0;i<n;i++){
        insert(root,data[i]);
    }
    return root;
}

删除

思路:删除的思路是四个中最复杂的,但是也是通过递归实现

① 若root为空,则说明不存在需要删除的值的节点,返回;

② 若root等于需要删除的值,则说明找到了需要删除的树节点,需要分类继续讨论:
        (1)不存在子节点,为叶子节点时,也是最方便的情况,直接将该节点进行删除节点,即root=NULL;

        (2)存在左子树,则将左子树中最大值向前覆盖,具体方法为找到左子树中的最大值所在节点,将其值赋给root,并删除该节点;

        (3)存在右子树,则将右子树中最小值向后覆盖,具体方法为找到右子树中的最小值所在节点,将其值赋给root,并删除该节点;

        (4)若左右子树都存在,只需执行(2)或(3)即可。

③ 若root大于需要删除的值,则在root的右子树中查找需要删除的树节点;

④ 若root小于需要删除的值,则在root的左子树中查找需要删除的树节点。

void delete(node* &root, int x){
    if(root == NULL){
        cout<<"不存在值为x的节点"<<endl;
        return;
    }
    if(root->val == x){
        if(!root->left && !root->right){
            root = NULL;
        }
        if(root->left){
            node* del = findmax(root->left);    //findmax就是查询树中最大值节点,自行实现吧!
            root->val = del->val;
            delete(root->left, del->val);
        }
        if(root->right){
            node* del = findmin(root->left);    //findmin就是查询树中最小值节点,自行实现吧!
            root->val = del->val;
            delete(root->right, del->val);
        }
    }
    else if(root->val > x){
        delete(root->left, x);
    }
    else{
        delete(root->right,x);
    }
}


平衡二叉树AVL

对二叉查找树的结构优化,若插入的元素一直比前序元素大时,则会得到链式树,无法起到二叉查找树简化查找的功能。为此,引入“平衡”的概念:左右子树的高度差绝对值不超过1,左右子树的高度差称为平衡因子(左子树高度-右子树高度).

为此树结点结构需要发生一点变化:

struct node{
    int v, height;    //v为结点的权重,height为当前子树的高度
    node *left, *right;
};

基本操作

查找(与BST完全相同)

void search(node* root, int x){
    if(root==NULL){
        cout<<"search failed."<<endl;
        return;
    }
    if(x==root->val){
        cout<<"search succeed."<<endl;
    }
    else if(x>root->val){
        search(root->right,x);
    }
    else{
        search(root->left,x);
    }
}

插入

讲到插入,得先了解左右旋(不是左旋鸡腿!)

左旋步骤:

① 将B的左子树变为A的右子树;

② 让A变为B的左子树;

③ 将B设为根节点。

void Left_Rotation(node* &root){
    node*temp = root->right;    //root=A,temp=B
    root->right = temp->left;
    temp->left = root;
    UpdateHeight(root);
    UpdateHeight(temp);
    root = temp;
}

右旋类似步骤:(代码略)

① 将A的右子树变为B的左子树;

② 让B变为A的右子树;

③ 将A设为根节点。

 接下来,考虑插入结点操作,当插入一个结点时,一定会有结点的平衡因子发生变化,若有结点的平衡因子绝对值大于1,则需要进行调整。只需要把靠近插入结点的失衡结点调整,该路径上左右的结点都会平衡。

插入情况分类:可以分为LL,LR,RR,RL四种情况,本文只介绍LL型和LR型(懒...)

LL型

 进行一次右旋即可实现平衡,将B变为根节点即可,在此不具体展示结果图,可参考右旋图思考。

LR型

如其名,先进行一次左旋,将其转换为LL型,再进行一次右旋,即可实现平衡, 实现图如下,最终结果图就是一个三层的满完全二叉树(不确定是不是这样叫的...)

 代码实现:
 

void insert(node* &root, int x){
    if(root==NULL){
        root = newNode(x);        //此处newNode为自建的新建节点API
        return;
    }
    if(x==root->val){
        cout<<"该值已经存在."<<endl;
        return;
    }
    else if{x>root->val}{
        insert(root->left,x);
        UpdateHeight(root);
        if(getBalanceFactor(root)==-2){
            if(getBalanceFactor(root->right)==-1){        //RR型
                L(root);
            }
            else if(getBalanceFactor(root->right)==1){    //RL型
                R(root->right);
                L(root);
            }
        }
    }
    else{
        insert(root->right,x);
        if(getBalanceFactor(root)==2){
            if(getBalanceFactor(root->right)==1){        //LL型
                R(root);
            }
            else if(getBalanceFactor(root->right)==-1){    //LR型
                L(root->left);
                R(root);
            }
        }
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值