红黑树的插入(中篇)

4 篇文章 0 订阅
3 篇文章 0 订阅

红黑树的插入

在一棵AVL树中,我们通过左旋和右旋来调整由于插入和删除所造成的不平衡问题。在红黑树中,可以使用两种方式进行平衡操作:

1. 重新着色
2. 旋转

旋转操作是二叉搜索树调整平衡的最好方法,因为不会打乱节点排列顺序,右旋操作,将左子树借一个节点给右子树,左旋操作,将右子树借一个节点给左子树,又因为红黑树有颜色的区分,也可以说是借颜色,为了保持红黑树黑色节点在路径上总和数量的相等。

当红黑树中出现不平衡的状态,我们首先会考虑重新着色,如果重新着色依旧不能使红黑树平衡,那么就考虑旋转。插入操作主要有两种情况,具体取决于叔叔结点的颜色。如果叔叔结点是红色的,我们会重新着色。如果叔叔结点是黑色的,我们会旋转或者重新着色,或者两者都考虑。

一个 NULL 结点被认为是黑色的,这在上篇已经提到过。
设 x 为新插入的结点,x节点设置为红色。

进行标准的 BST 插入并将新插入的结点设置为红色。
1.如果 x 的父结点 p 是黑色并且 x 不是根结点
2.如果 x 是根结点,将 x 的颜色转化为黑色(整棵树的黑高增加 1)。
3.如果 x 的父结点 p 是红色并且 x 不是根结点,则:
	a). 如果 x 的叔叔结点 u 是红色。
		将插入结点 x 的父结点(Parent )p 和叔叔(uncle)结点 u 的颜色变为黑色;
		将 x 的爷爷结点(Grand Parent)g 设置为红色;
		将 x = x的爷爷结点 g ,对于新的 x 重复 2,3两步。
	b). 如果 x 的叔叔结点 u 是黑色,则对于 x、 x 的父结点 p 和 x 的爷爷结点 g有以下四种情况:
 		LL(p 是 g 的左孩子且 x 是 p 的左孩子)
		LR(p 是 g 的左孩子且 x 是 p 的右孩子)
		RR(p 是 g 的右孩子且 x 是 p 的右孩子)
		RL(p 是 g 的右孩子且 x 是 p 的左孩子)

情况1

标准的BST插入,插入节点的父节点是黑色,插入节点x本身是红色。那么什么都不需要操作了,满足红黑树性质。
因为x节点父子节点都是黑色的,符合红黑树性质。
在这里插入图片描述

情况2

插入节点是根节点,那么将插入节点x设置为黑色,红黑树性质要求根节点需要是黑色。
在这里插入图片描述

情况3

如果 x 的父结点 p 是红色并且 x 不是根结点。由于x的父节点是红色,那么说明祖父节点是黑色,因为红色节点不能相邻,所以可以判断叔叔节点的颜色是红色和黑色两种情况,对应如下分为3.1,3.2两种情况:

情况3.1

a) 如果 x 的叔叔结点 u 是红色。
		将插入结点 x 的父结点(Parent )p 和叔叔(uncle)结点 u 的颜色变为黑色;
		将 x 的爷爷结点(Grand Parent)g 设置为红色;
		将 x = x的爷爷结点 g ,对于新的 x 重复 2,3两步。

在这里插入图片描述
首先将2,15节点设置成黑色,将6节点设置成红色,插入节点x重新赋值为x的祖父节点6,然后从节点6开始重复2,3的流程。
在这里插入图片描述
至于什么时候终止向上递归,那么要取决于插入节点x的所遇到的情况,能不能符合红黑树的性质。

情况3.2

b). 如果 x 的叔叔结点 u 是黑色,则对于 x、 x 的父结点 p 和 x 的爷爷结点 g有以下四种情况:
 		LL(p 是 g 的左孩子且 x 是 p 的左孩子)
		LR(p 是 g 的左孩子且 x 是 p 的右孩子)
		RR(p 是 g 的右孩子且 x 是 p 的右孩子)
		RL(p 是 g 的右孩子且 x 是 p 的左孩子)
LL
	LL(p 是 g 的左孩子且 x 是 p 的左孩子)

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

左边插入了x节点之后,多出来一个红色节点,需要进行右旋将红色节点借到右边去,因为右边有两个黑色节点,可以容纳更多一个红色节点,但是左边不允许,那么具体的操作就是:1.将祖父节点的颜色和父节点的颜色互换;2.右旋节点祖父节点6。

LR
	LR(p 是 g 的左孩子且 x 是 p 的右孩子)

在这里插入图片描述

这种情况其实和LL情况差不多,可以将LR情况转化成LL情况之后,在使用LL的操作方式进行红黑树平衡操作。
将2设为新插入的节点X,进行LL操作。

在这里插入图片描述在这里插入图片描述

RR
		RR(p 是 g 的右孩子且 x 是 p 的右孩子)

在这里插入图片描述
操作其实和LL差不多,只不过是对称操作。1.将15节点和6节点的颜色互换;2.节点6左旋。
在这里插入图片描述在这里插入图片描述

RL
		RL(p 是 g 的右孩子且 x 是 p 的左孩子)

在这里插入图片描述
RL节点情况可以转化成RR的情况,先右旋15节点,转化成了RR的情况,根据RR情况进行操作:
在这里插入图片描述在这里插入图片描述

操作代码

红黑树结构:

    public class TreeNode {
        public T value = null;
        public TreeNode parent = null;
        public TreeNode left = null;
        public TreeNode right = null;
        public NodeColor color;

        public TreeNode(NodeColor color) {
            this.color = color;
        }

        public TreeNode(T value,NodeColor color) {
            this.value = value;
            this.color = color;
        }
    }

左右旋操作:

 private void rotateLeft(TreeNode subRoot) {
        //右节点不为空,才能左旋
        if (subRoot.right != null && subRoot.right.value != null) {
            TreeNode right = subRoot.right;
            TreeNode rl = right.left;

            TreeNode parent = subRoot.parent;
            if (parent != null) {
                if (parent.left == subRoot) {
                    parent.left = right;
                } else if (parent.right == subRoot) {
                    parent.right = right;
                }
            }
            right.parent = parent;

            right.left = subRoot;
            subRoot.parent = right;

            subRoot.right = rl;
            if (rl != null) {
                rl.parent = subRoot;
            }

            if (subRoot == root) {
                root = subRoot.parent;
            }
        }
    }

    private void rotateRight(TreeNode subRoot) {
        //右节点不为空,才能左旋
        if (subRoot.left != null && subRoot.left.value != null) {
            TreeNode left = subRoot.left;
            TreeNode lr = left.right;

            TreeNode parent = subRoot.parent;
            if (parent != null) {
                if (parent.left == subRoot) {
                    parent.left = left;
                } else if (parent.right == subRoot) {
                    parent.right = left;
                }
                left.parent = parent;
            }

            left.right = subRoot;
            subRoot.parent = left;

            subRoot.left = lr;
            if (lr != null) {
                lr.parent = subRoot;
            }

            if (subRoot == root) {
                root = subRoot.parent;
            }
        }
    }

BST插入操作:

        //常规bst插入操作
        TreeNode indexNode = root;
        while (indexNode != null && indexNode.value != null) {
            if (val.compareTo(indexNode.value) > 0) {
                indexNode = indexNode.right;
            } else {
                indexNode = indexNode.left;
            }
        }

        if (indexNode != null && indexNode.parent != null) {
            TreeNode newNode = new TreeNode(val,NodeColor.RED);

            //插入的具体实现
            insertNodeInner(indexNode,newNode);

            //插入后,平衡操作
            BalanceTreeForInserted(newNode);
        }

平衡操作:


    private void BalanceTreeForInserted(TreeNode newNode) {
        TreeNode parent = newNode.parent;

        if (newNode == root && newNode.parent == null) {
            newNode.color = NodeColor.BLACK;
            return;
        }

        //2.1 插入节点父亲节点是黑色,不用调整,结束
        if (parent.color == NodeColor.BLACK) {
            return;
        }

        //2.2 插入节点父亲节点是红色,插入后需要调整(父节点是红,那么一定有祖父节点,红节点不能是红色)
        if (parent.color == NodeColor.RED){
            TreeNode grandParent = parent.parent;

            boolean cl = false;
            if (parent.left == newNode) {
                cl = true;
            } else if (parent.right == newNode) {
                cl = false;
            }

            TreeNode uncle = null;
            boolean pl = false;
            if (grandParent.left == parent) {
                uncle = grandParent.right;
                pl = true;
            } else if (grandParent.right == parent) {
                uncle = grandParent.left;
                pl = false;
            }

            if (uncle != null) {
                if (uncle.color == NodeColor.RED){
                    uncle.color = NodeColor.BLACK;
                    parent.color = NodeColor.BLACK;
                    grandParent.color = NodeColor.RED;
                    BalanceTreeForInserted(grandParent);
                } else if (uncle.color == NodeColor.BLACK) {
                    if (pl) { //LL.LR两种情况
                        if (!cl) {
                            rotateLeft(parent);
                        }
                        grandParent.color = NodeColor.RED;
                        grandParent.left.color = NodeColor.BLACK;
                        rotateRight(grandParent);
                    } else {//RR,RL两种情况
                        if (cl) {
                            rotateRight(parent);
                        }
                        grandParent.color = NodeColor.RED;
                        grandParent.right.color = NodeColor.BLACK;
                        rotateLeft(grandParent);
                    }
                }
            }
        }
    }

总结

模拟红黑树操作的在线网站,强烈推荐:点我

下一篇,我将讲解红黑树的删除操作,比插入操作要复杂一些,点我。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值