算法导论之红黑树

红黑树是特殊的搜索树,除了要满足搜索树外,还得满足color的要求。原则上说树的所有操作只有两种:插入和删除。
基本知识左旋、右旋、最小后继和节点替换不在重复。只针对插入和删除,说其内部原理。

插入:

插入一个元素时,由于红黑树根本也是一棵搜索树,所以可以先用搜索树的方式插入一个元素。由于在末尾添加的元素,如果置黑,可能导致其他树的黑路径长度少一。置红的话就不存在这个问题,只会存在两个红节点相邻的问题。解决这个问题,比较简单:两个红节点相邻,则下方的红节点树一定排列正确,只需要考虑上方的节点,通过左旋或者右旋将红节点不停往上传递即可。

删除:

删除任意一个节点,和搜索树一样,如果该节点有单子树,只需要将单树替换到该节点(注意颜色不改变)即可,否则,其他的删除,从本质上来说都是删除叶子结点。
如果删除的节点是黑色,会导致该树上黑色节点数目少一,为保持平衡,则将替换的nil置“双黑”,然后根据算法导论书上的描述处理即可。这里只注意nil是黑节点(虽然我们是用null替代的),故为了处理方便,我在fix上额外添加了一个参数parent。

具体实现请查看代码,细节问题可以讨论,如果哪里写错了,欢迎指正!

#define RED 1
#define BLACK 0

typedef struct TreeNode
{
    TreeNode* left;
    TreeNode* right;
    TreeNode* parent;
    int value;
};

typedef struct TreeNodeColor : public TreeNode
{
    int color;
};

typedef struct Tree
{
    TreeNode* root;
};

//一定存在右子节点
void Left_Rotate(Tree *root, TreeNode *node)
{
    if (!node || !node->right)
    {
        return;
    }
    TreeNode* right = node->right;
    node->right = right->left;
    if (right->left != NULL)
    {
        right->left->parent = node;
        right->left = node;
    }

    TreeNode* parent = node->parent;
    node->parent = right;
    if (parent != NULL)
    {
        if (parent->left == node)
        {
            parent->left = right;
        }
        else
        {
            parent->right = right;
        }
    }
    else
    {
        root->root = right;
    }
    right->parent = parent;
}

//一定有父节点
void Right_Rotate(Tree *root, TreeNode *node)
{
    if (!node || !node->parent)
    {
        return;
    }
    TreeNode* parent = node->parent;
    parent->left = node->right;
    node->right = parent;
    TreeNode* temp = parent->parent;

    if (temp != NULL)
    {
        if (temp->left == parent)
        {
            temp->left = node;
        }
        else
        {
            temp->right = node;
        }
    }
    else
    {
        root->root = node;
    }
    if (parent->left != NULL)
    {
        parent->left->parent = parent;
    }
}

void Rotate(Tree* root, TreeNode* node, int isLeft)
{
    if (isLeft)
    {
        Left_Rotate(root, node);
    }
    else
    {
        Right_Rotate(root, node);
    }
}

//node的父树的两个子树肯定已经排好了,处理父树就好了
//只需要处理红节点,则node对应的肯定是红节点
//这个过程处理结束后,只剩下根节点,最后将其重置为红色即可
void insertFixupWithoutRoot(Tree* root, TreeNodeColor* node)
{
    if (node == NULL)
    {
        return;
    }
    TreeNodeColor* parent = (TreeNodeColor*)node->parent;
    //必要条件:node有父  node的父为红节点 
    //node的父树一定也有父,如果没有父说明处理到根节点,当返回了 
    if (parent && parent->parent&& parent->color == RED)
    {
    TreeNodeColor* other;
    int flag_parent = 1, flat_cur = 1;
    //找到p->p的另一个子节点
    if (parent->parent->left == parent)
    {
        other = (TreeNodeColor*)parent->right;
    }
    else
    {
        other = (TreeNodeColor*)parent->left;
        flag_parent = 0;
    }
    if (parent->right == node)
    {
        flat_cur = 0;
    }
    if (!other && other->color == RED)//会产生红节点,并会影响到对其父树
    {
        other->color = BLACK;
        node->color = BLACK;
        parent->color = RED;
        insertFixupWithoutRoot(root, parent);
    }
    else//会产生红节点,通过旋转,被内部消化
    {
        if (flag_parent != flat_cur)
        {
            node = parent;
            if (flat_cur)
            {
                Left_Rotate(root, parent);
            }
            else
            {
                Right_Rotate(root, parent);
            }
        }
        ((TreeNodeColor*)node->parent)->color = BLACK;
        //在旋转过后这个红节点不会有影响
        ((TreeNodeColor*)node->parent->parent)->color = RED;
        if (flag_parent)
        {
            Right_Rotate(root, node->parent->parent);
        }
        else
        {
            Left_Rotate(root, node->parent->parent);
        }
    }
    }
}

//添加黑节点后稳固树
void insert_fixup(Tree* root, TreeNodeColor* node)
{
    //先处理完所有非根节点
    insertFixupWithoutRoot(root, node);
    //重置根节点颜色
    ((TreeNodeColor*)root->root)->color = BLACK;
}

//删除黑节点后平衡整个树
void delete_fixup(Tree* root, TreeNodeColor* node, TreeNodeColor* parent)
{
    if (parent == NULL)
    {
        return;
    }
    TreeNodeColor* other;

    if (parent->left == node)
    {
        other = (TreeNodeColor*)parent->right;
    }
    else
    {
        other = (TreeNodeColor*)parent->left;
    }
    TreeNodeColor* other_left = (TreeNodeColor*)other->left;
    TreeNodeColor* other_right = (TreeNodeColor*)other->right;
    if (other->color == RED) // case 1
    {
        Rotate(root, parent, node == parent->left);
        delete_fixup(root, node, parent);
    }
    else if ((!other_left || other_left->color == BLACK) && (!other_right || other_right->color == BLACK)) // case 2
    {
        int color = parent->color;
        parent->color = BLACK;
        other->color = RED;
        if (color == BLACK)
        {
            delete_fixup(root, parent, (TreeNodeColor*)parent->parent);
        }
    }
    else if (other_left && other_left->color == RED && (!other_right || other_right->color == BLACK)) //case 3
    {
        other_left->color = BLACK;
        other->color = RED;
        Rotate(root, parent, false);
        delete_fixup(root, node, parent);
    }
    else if (other_right && other_right->color == RED) // case 4
    {
        int color = parent->color;
        other_right->color = BLACK;
        parent->color = BLACK;
        other->color = color;
        Rotate(root, parent, true);
    }
}

void insert(Tree *root, TreeNodeColor* node)
{
    TreeNode *parent = node->parent, *cur = root->root;
    while (cur != NULL)
    {
        parent = cur;
        if (cur->value < node->value)
        {
            cur = cur->right;
        }
        else
        {
            cur = cur->left;
        }
    }
    if (parent == NULL)
    {
        root->root = node;
    }
    else
    {
        if (parent->value < node->value)
        {
            parent->right = node;
        }
        else
        {
            parent->left = node;
        }
    }
    node->parent = parent;
    node->color = RED;
    insert_fixup(root, node);
}

//节点替换
void transplant(Tree* root, TreeNode* node, TreeNode* replace_node)
{
    if (node && node->parent)
    {
        if (node->parent->left == node)
        {
            node->parent->left = replace_node;
        }
        else
        {
            node->parent->right = replace_node;
        }
    }
    else
    {
        root->root = replace_node;
    }
    if (replace_node)
    {
        replace_node->parent = node->parent;
    }
}

TreeNode* minmum(TreeNode *node)
{
    TreeNode *result = node;
    while (result->left)
    {
        result = result->left;
    }
    return result;
}

//删除黑节点时,会导致一部分树出现失衡
//出现失衡后,需要将多余的黑树上报给根节点
void del(Tree *root, TreeNodeColor* node)
{
    int color;
    if (!node->left || !node->right)//单子树肯定不会存在右子树为黑的情况
    {
        TreeNodeColor* temp = (TreeNodeColor*)(node->left ? node->left : node->right);
        transplant(root, node, temp);
        if (temp)
        {
            temp->color = node->color;
        }
        else if(node->color == BLACK)
        {
            delete_fixup(root, NULL, (TreeNodeColor*)node->parent);
        }
    }
    else
    {
        TreeNodeColor* min = (TreeNodeColor*)minmum(node->right);
        node->value = min->value;
        del(root, min);
    }
    ((TreeNodeColor*)root->root)->color = BLACK;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值