红黑树insert操作

一、红黑树的insert理论

  1. 当前树为空树时,插入的节点是根节点,即黑色
  2. 当前树非空时,插入节点为叶子节点,若插入的叶子节点为黑色,那每次插入都会破坏性质5。为了避免每次插入都要进行相应的旋转维持红黑树性质,插入的所有叶子节点都是红色。由于不能出现连续的红色节点,所以需要检查父节点的颜色。若父节点为黑色,则插入完成,否则出现连续的红色节点需要做相应的调整:

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


在这里插入图片描述

在这里插入图片描述
这样就保持了局部和原来一样的红黑树的性质,所以全局也是保持了性质,调整完成!!!


在这里插入图片描述
在情况3中,使用交换颜色和右旋转的方法,也会产生连续两个红色节点的问题

其实这种情况很好解决,把B和C旋转到一条线上,就可以使用情况2的方法解决了
在这里插入图片描述
插入情况总结:

  • 情况1中叔叔是红色,插入到叶子节点的左侧或右侧;需要把父亲和叔叔置为黑色,爷爷置为红色,当前node指向爷爷,然后接着向上调整祖先节点
  • 情况2中叔叔是黑色,插入到叶子节点的左侧;交换父亲和爷爷的颜色,然后以父亲为轴右旋转
  • 情况3中叔叔是黑色,插入到叶子节点的右侧;以父亲为轴进行左旋转,将父亲、爷爷、叶子节点掰到同一侧,然后用情况2的方式处理

二、insert代码实现

void insert(const T& val) {
	if (root_ == nullptr) {
		root_ = new Node(val);
		return;
	}
	Node* parent = nullptr;
	Node* cur = root_;
	while (cur != nullptr) {
		if (cur->data_ > val) {
			parent = cur;
			cur = cur->right_;
		}
		else if (cur->data_ < val) {
			parent = cur;
			cur = cur->right_;
		}
		else {
			return;
		}
	}
	// 设置当前节点的parent和color
	Node* node = new Node(val, parent, nullptr, nullptr, Color::RED);
	if (parent->data_ > val) {
		parent->left_ = node;
	}
	else {
		parent->right_ = node;
	}

	// 插入节点的父节点也是红色,则出现连续的红色,需要调整
	if (Color::RED == color(parent)) {
		fixAfterInsert(node);
	}
}

void fixAfterInsert(Node* node) {
	// 父节点的颜色是红色,当前节点也是红色,不断调整
	while (color(parent(node)) == Color::RED) {
		// 父节点是爷爷的左孩子,插入的节点node在左子树
		if (parent(node) == left(parent(parent(node)))) {
			// 父亲是爷爷的左孩子,叔叔是爷爷的右孩子
			Node* uncle = right(parent(parent(node)));
			// 情况1:叔叔是红色(无论在父亲左侧或右侧)
			if (Color::RED == color(uncle)) {
				// 因为叔叔和父亲原来都是RED,爷爷原来必然是BLACK,上两代互换颜色
				setColor(parent(node), Color::BLACK);
				setColor(uncle, Color::BLACK);
				setColor(parent(parent(node)), Color::RED);
				// 上两代互换颜色后,爷爷变成RED,由于爷爷以前是BLACK,也许爷爷的父亲是RED,现在爷爷变RED后,可能连续出现两个RED,需要继续向上调整
				node = parent(parent(node));
			}
			else {
				// 情况2/3:叔叔是BLACK
				// 先处理叔叔是BLACK,插到叶子节点右侧的情况3
				if (node == right(parent(node))) {
					// 让node指向父亲,以node为轴旋转后,node才能成为情况2中刚插入的节点,进而统一情况2、3
					node = parent(node);
					leftRotate(node);
				}
				// 统一成情况2,叔叔是BLACK,插到叶子节点左侧
				setColor(parent(node), Color::BLACK);
				setColor(parent(parent(node)), Color::RED);
				rightRotate(parent(parent(node)));
				// 情况2、3保证了局部没有出现连续的RED,且保证了修改的局部支路中黑色节点数量没变,即全局也没有改变
				// 情况1只是修改颜色,情况2、3最多旋转两次,至此红黑树调整完成
				break;
			}
		}
		else {
			// 父节点是爷爷的右孩子,插入的节点node在右子树
			// 父亲是爷爷的右孩子,叔叔是爷爷的左孩子
			Node* uncle = left(parent(parent(node)));
			// 情况1:叔叔是红色(无论在父亲左侧或右侧)
			if (Color::RED == color(uncle)) {
				// 因为叔叔和父亲原来都是RED,爷爷原来必然是BLACK,上两代互换颜色
				setColor(parent(node), Color::BLACK);
				setColor(uncle, Color::BLACK);
				setColor(parent(parent(node)), Color::RED);
				// 上两代互换颜色后,爷爷变成RED,由于爷爷以前是BLACK,也许爷爷的父亲是RED,现在爷爷变RED后,可能连续出现两个RED,需要继续向上调整
				node = parent(parent(node));
			}
			else {
				// 情况2/3:叔叔是BLACK
				// 先处理叔叔是BLACK,插到叶子节点左侧的情况3
				if (node == left(parent(node))) {
					// 让node指向父亲,以node为轴旋转后,node才能成为情况2中刚插入的节点,进而统一情况2、3
					node = parent(node);
					rightRotate(node);
				}
				// 统一成情况2,叔叔是BLACK,插到叶子节点右侧
				setColor(parent(node), Color::BLACK);
				setColor(parent(parent(node)), Color::RED);
				leftRotate(parent(parent(node)));
				// 情况2、3保证了局部没有出现连续的RED,且保证了修改的局部支路中黑色节点数量没变,即全局也没有改变
				// 情况1只是修改颜色,情况2、3最多旋转两次,至此红黑树调整完成
				break;
			}
		}
	}
	// 此处需要将root_置为黑色
	setColor(root_, Color::BLACK);
}

红黑树插入1…10的过程如下:

在这里插入图片描述
插入红色节点3,交换红色父亲2和黑色爷爷1的颜色后,以爷爷1为轴左旋转


在这里插入图片描述
叔叔为红色,将父亲和叔叔的颜色置为黑色,爷爷置为红色,当前节点node指向爷爷,继续向上调整


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


红黑树插入1…39的结果如下:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bugcoder-9905

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值