红黑树概念和旋转实现

一、红黑树的概念

不是一颗平衡树,节点的左右子树高度大的不超过高度小的两倍。在满足红黑树性质的前提下,旋转的次数要远小于AVL树,虽然红黑树不想AVL树那样平衡,也不会像BST树一样,有序插入会形成一个链表

而AVL树是平衡树,任意节点左右子树高度差不超过1,从根节点到任意叶子节点的距离都是相当的,即 查询效率高。然后AVL树旋转的次数和高度相关,有可能从失衡节点往根节点回溯的过程中有很多失衡节点,这都需要进行旋转,时间复杂度为 O ( l o g 2 n ) O(log_2n) O(log2n)。而红黑树remove后最多旋转3次

在这里插入图片描述
红黑树特点:

  • 树的每一个节点不是黑色就是红色
  • root是黑色
  • null是黑色
  • 从根节点到每一个叶子节点的所有路径上,不能出现连续的红色节点。即父亲是红色,孩子一定全是黑色;如果孩子有红色,父亲一定是黑色
  • 从任一节点到其每个叶子节点的所有路径上,黑色节点的数量是相同的
操作AVL红黑树
平衡树
增删查时间复杂度O(logn)O(logn)
insert最多旋转的次数22
remove最多旋转的次数O(logn)3

如果remove的场景少,可以考虑使用AVL树,如果多,就使用红黑树。C++的map、multimap、set、multiset的底层数据结构就是红黑树,这是因为我们使用容器的时候,增删改查都需要用到,而且频率相当

思考题:在红黑树中,节点的左右子树的高度差最多不能超过多少?

左右子树高度差最多不超过两倍
在这里插入图片描述

二、红黑树的定义代码

在红黑树中,访问节点的时候,要访问到它的父亲,爷爷和叔叔,需要方便的访问到父节点

在递归的过程中就不方便了,而且对于红黑树来说,插入操作最多旋转2次,局部解决完之后,局部没有改变红黑树的性质,全局自然就维护了红黑树的性质,局部解决好了,就不用向上回溯了,所以我们不需要使用递归,递归的话要从插入的地方回溯到根节点,效率低

template<typename T>
class RBTree {
public:
	RBTree():root_(nullptr){}


private:
	enum Color {
		RED,
		BLACK
	};

	struct Node {
		Node(T data=T(), Color color=BLACK, Node* parent=nullptr, Node* left=nullptr, Node* right=nullptr)
			: data_(data)
			, color_(color)
			, parent_(parent)
			, left_(left)
			, right_(right)
		{}

		T data_;
		Color color_;
		Node* left_;
		Node* right_;
		Node* parent_;  // 用于向上访问
	};
	
	Node* root_;
};

三、红黑树的左旋转和右旋转代码

AVL树的左旋转代码
在这里插入图片描述
AVL树的旋转代码只改了孩子域,父亲域是回溯时利用返回值改的,我们写红黑树代码是非递归形式的,所以需要手动改6个地址域
在这里插入图片描述
红黑树的旋转和AVL树的旋转一样的,只是多了一个parent,代码基于AVL树改即可

void leftRotate(Node* node) {
	Node* child = node->right_;
	// 1
	child->parent_ = node->parent_;
	if (node->parent_ == nullptr) {
		// node的父节点为空,说明node为root,此时child转上来,child成为root
		root_ = child;
	}
	else {
		// node不是root
		if (node->parent_->left_ == node) {
			// node是左孩子  2
			node->parent_->left_ = child;
		}
		else {
			// node是右孩子
			node->parent_->right_ = child;
		}
	}

	// 3
	node->right_ = child->left_;
	if (child->left_ != nullptr) {
		// 4
		child->left_->parent_ = node;
	}
	// 5
	child->left_ = node;
	// 6
	node->parent_ = child;
}

AVL树的右旋转代码
在这里插入图片描述
在这里插入图片描述

// 以node为轴进行右旋
void rightRotate(Node* node) {
	Node* child = node->left_;
	child->parent_ = node->parent_;        // 1
	if (node->parent_ == nullptr) {
		// node就是root
		root_ = child;
	}
	else {
		// node不是root
		if (node->parent_->left_ == node) {
			// node是左孩子
			node->parent_->left_ = child;   // 2
		}
		else {
			// node是右孩子
			node->parent_->right_ = child;
		}
	}

	node->left_ = child->right_;           // 3
	if (child->right_ != nullptr) {
		child->right_->parent_ = node;     // 4
	}
	child->right_ = node;                  // 5
	node->parent_ = child;                 // 6
}

红黑树插入1…10的过程如下:
在这里插入图片描述

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
红黑树是一种自平衡二叉查找树,它保证了在最坏情况下基本动态集合操作的时间复杂度为O(log n)。红黑树的每个节点都有一个颜色属性,可以是红色或黑色。红黑树满足以下5个性质: 1. 每个节点要么是红色,要么是黑色。 2. 根节点是黑色。 3. 每个叶子节点(NIL节点,空节点)是黑色的。 4. 如果一个节点是红色的,则它的两个子节点都是黑色的。 5. 对于每个节点,从该节点到其所有后代叶子节点的简单路径上,均包含相同数目的黑色节点。 红黑树的三种操作包括插入、删除和查找。插入和删除操作需要通过旋转和颜色修改来保证红黑树的性质不被破坏。以下是Python代码实现红黑树的三种操作和扩张: ```python class Node: def __init__(self, key): self.key = key self.left = None self.right = None self.parent = None self.color = 1 class RedBlackTree: def __init__(self): self.null_node = Node(0) self.null_node.color = 0 self.null_node.left = None self.null_node.right = None self.root = self.null_node def left_rotate(self, x): y = x.right x.right = y.left if y.left != self.null_node: y.left.parent = x y.parent = x.parent if x.parent == self.null_node: self.root = y elif x == x.parent.left: x.parent.left = y else: x.parent.right = y y.left = x x.parent = y def right_rotate(self, x): y = x.left x.left = y.right if y.right != self.null_node: y.right.parent = x y.parent = x.parent if x.parent == self.null_node: self.root = y elif x == x.parent.right: x.parent.right = y else: x.parent.left = y y.right = x x.parent = y def insert(self, key): node = Node(key) node.parent = None node.key = key node.left = self.null_node node.right = self.null_node node.color = 1 y = None x = self.root while x != self.null_node: y = x if node.key < x.key: x = x.left else: x = x.right node.parent = y if y == None: self.root = node elif node.key < y.key: y.left = node else: y.right = node if node.parent == None: node.color = 0 return if node.parent.parent == None: return self.fix_insert(node) def fix_insert(self, k): while k.parent.color == 1: if k.parent == k.parent.parent.right: u = k.parent.parent.left if u.color == 1: u.color = 0 k.parent.color = 0 k.parent.parent.color = 1 k = k.parent.parent else: if k == k.parent.left: k = k.parent self.right_rotate(k) k.parent.color = 0 k.parent.parent.color = 1 self.left_rotate(k.parent.parent) else: u = k.parent.parent.right if u.color == 1: u.color = 0 k.parent.color = 0 k.parent.parent.color = 1 k = k.parent.parent else: if k == k.parent.right: k = k.parent self.left_rotate(k) k.parent.color = 0 k.parent.parent.color = 1 self.right_rotate(k.parent.parent) if k == self.root: break self.root.color = 0 def get_root(self): return self.root def search_tree(self, node, key): if node == self.null_node or key == node.key: return node if key < node.key: return self.search_tree(node.left, key) return self.search_tree(node.right, key) def find_kth_smallest(self, node, k): left_size = node.left.size if node.left else 0 if k <= left_size: return self.find_kth_smallest(node.left, k) elif k == left_size + 1: return node else: return self.find_kth_smallest(node.right, k - left_size - 1) def size(self, node): if node == self.null_node: return 0 return 1 + self.size(node.left) + self.size(node.right) def insert_node(self, node): y = None x = self.root while x != self.null_node: y = x if node.key < x.key: x = x.left else: x = x.right node.parent = y if y == None: self.root = node elif node.key < y.key: y.left = node else: y.right = node node.left = self.null_node node.right = self.null_node node.color = 1 if node.parent == None: node.color = 0 return if node.parent.parent == None: return self.fix_insert(node) # 扩展:红黑树的删除操作 def delete_node(self, node): if node == self.null_node: return y = node y_original_color = y.color if node.left == self.null_node: x = node.right self.transplant(node, node.right) elif node.right == self.null_node: x = node.left self.transplant(node, node.left) else: y = self.minimum(node.right) y_original_color = y.color x = y.right if y.parent == node: x.parent = y else: self.transplant(y, y.right) y.right = node.right y.right.parent = y self.transplant(node, y) y.left = node.left y.left.parent = y y.color = node.color if y_original_color == 0: self.fix_delete(x) def fix_delete(self, x): while x != self.root and x.color == 0: if x == x.parent.left: s = x.parent.right if s.color == 1: s.color = 0 x.parent.color = 1 self.left_rotate(x.parent) s = x.parent.right if s.left.color == 0 and s.right.color == 0: s.color = 1 x = x.parent else: if s.right.color == 0: s.left.color = 0 s.color = 1 self.right_rotate(s) s = x.parent.right s.color = x.parent.color x.parent.color = 0 s.right.color = 0 self.left_rotate(x.parent) x = self.root else: s = x.parent.left if s.color == 1: s.color = 0 x.parent.color = 1 self.right_rotate(x.parent) s = x.parent.left if s.right.color == 0 and s.right.color == 0: s.color = 1 x = x.parent else: if s.left.color == 0: s.right.color = 0 s.color = 1 self.left_rotate(s) s = x.parent.left s.color = x.parent.color x.parent.color = 0 s.left.color = 0 self.right_rotate(x.parent) x = self.root x.color = 0 def transplant(self, u, v): if u.parent == None: self.root = v elif u == u.parent.left: u.parent.left = v else: u.parent.right = v v.parent = u.parent def minimum(self, node): while node.left != self.null_node: node = node.left return node # 示例 tree = RedBlackTree() tree.insert_node(Node(10)) tree.insert_node(Node(20)) tree.insert_node(Node(30)) tree.insert_node(Node(100)) tree.insert_node(Node(90)) tree.insert_node(Node(40)) tree.insert_node(Node(50)) tree.insert_node(Node(60)) tree.insert_node(Node(70)) tree.insert_node(Node(80)) print(tree.find_kth_smallest(tree.get_root(), 3).key) # 输出30 --相关问题--:

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

bugcoder-9905

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

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

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

打赏作者

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

抵扣说明:

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

余额充值