左倾红黑树

左倾红黑树 ( L L R B ) (LLRB) (LLRB)

左倾红黑树从概念上讲是一颗2-3树,不过这颗2-3树是使用二叉树形式实现的。
每个节点都有一个颜色,如果是红色,表示该节点的父亲该节点组成了2-3树中的3叉节点,即利用节点和其颜色信息联合起来 表示2-3树中的3叉节点。
在这里插入图片描述

旋转操作

在这里插入图片描述

NODE* LBTree::rotate_left(NODE* node) {
	NODE* res = node->rc;
	node->rc = res->lc;
	res->lc = node;

	swap(res->color, node->color);
	return res;
}

在这里插入图片描述

NODE* LBTree::rotate_right(NODE* node) {
	NODE* res = node->lc;
	node->lc = res->rc;
	res->rc = node;

	swap(res->color, node->color);
	return res;
}
插入

插入的过程完全可以类比2-3树的插入:

  • 如果待插入的叶子节点只有一个键,那么直接插入,类比到左倾红黑树,就是插入到该叶子节点的左侧(如果是右侧则左旋),并置节点的颜色为红色。
    在这里插入图片描述

  • 如果 被插入的叶子节点有两个键,也就是节点满了,那么先插进去形成3个键的临时节点(4叉节点),然后选择中间的键交给其父亲节点,自身再分裂成两个节点,每个节点含有一个键。类比到左倾红黑树,插入到叶子节点的左侧(如果是右侧则左旋),然后叶子节点的父亲右旋,并改变它们的颜色(取反),实际上取反对应的就是4叉节点的分裂。
    在这里插入图片描述

// 颜色取反操作
void LBTree::color_flip(NODE* node) {
	node->color ^= 1;
	if (node->lc) node->lc->color ^= 1;
	if (node->rc) node->rc->color ^= 1;
}

NODE* LBTree::fix_up(NODE* node) {
	if (!is_red(node->lc) && is_red(node->rc))
		node = rotate_left(node);
	if (is_red(node->lc) && is_red(node->lc->lc))
		node = rotate_right(node);
	if (is_red(node->lc) && is_red(node->rc))
		color_flip(node);   
	return node;
}

NODE* LBTree::Insert(NODE* _root, int key) {
	if (_root == nullptr) {
		return new NODE(key, KRED);
	}
	if (key == _root->key)
		;
	else if (key < _root->key) 
		root->lc = Insert(root->lc, key);
	else
		root->rc = Insert(root->rc, key);
	return fix_up(_root);
}
删除

没法和2-3树的删除进行类比。

删除节点分为两种情况:删除叶子节点和删除内部节点,但删除内部节点可以转化为删除叶子节点(假设读者已知二叉搜索树的删除过程),所以合并成一种情况考虑。考虑删除叶子节点:如果叶子节点是红色节点,直接删除不会影响黑色平衡。如果是黑色节点,则没法直接删了。所以为了让待删除的叶子节点一定是红色节点,在向下搜索的过程中保证当前节点的儿子是红色边的端点,即node->child is red || node->child->child is red,怎么保证喃?如果当前节点的儿子和当前节点的儿子的儿子都不是红色节点,则翻转当前节点及它儿子的颜色,回溯的时候再修复。论文Left-leaning Red-Black Trees 叙述了这个操作,且不会影响树的平衡。
在这里插入图片描述
上图翻转的操作将 h h h变成了2-3树中的4叉节点,注意到没,这和插入节点是相反的过程。
删除的过程有一点与2-3树删除共通:可以从右兄弟节点借一个键过来。
在这里插入图片描述

NODE* LBTree::Delete_min(NODE* node) {
	if (node->lc == nullptr) {
		delete node;
		return nullptr;
	}
	if (!is_red(node->lc) && !is_red(node->lc->lc))
		node = move_red2left(node);     // 能从右儿子借最好,不能的话临时合并成4叉节点
	node->lc = Delete_min(node->lc);
	return fix_up(node);
}

NODE* LBTree::Delete_arby(NODE* _root, int key) {
	if (_root == nullptr) return nullptr;
	if (key < _root->key) {
		if (!is_red(_root->lc) && !is_red(_root->lc->lc))
			_root = move_red2left(_root);
		_root->lc = Delete_arby(_root->lc, key);
	}
	else {
		if (is_red(_root->lc)) _root = rotate_right(root);  // 右旋使得右儿子是红色节点 
		if (key == _root->key && _root->rc == nullptr) {    // 已经到了叶子,直接删除
			delete _root;
			return NULL;
		}
		if (!is_red(_root->rc) && !is_red(_root->rc->lc))  // 能从左儿子借最好,不能的话合并成4叉节点
			_root = move_red2right(_root);
		if (key == _root->key) {
			_root->key = get_min(_root);
			_root->rc = Delete_min(_root->rc);
		}
		else
			_root->rc = Delete_arby(_root->rc, key);
	}
	return fix_up(_root);
}
参考

1.Left-leaning Red-Black Trees
2. https://oi-wiki.org/ds/llrbt/【强烈推荐】

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值