python 红黑树_红黑树(一):插入

我们讲二叉树啊,平衡树的旋转啊,费了那么多劲,目的就是为了引出今天的主题:红黑树。红黑树是JDK中最重要的一个树型数据结构。TreeSet, TreeMap,以及最新的Hashtable都使用了红黑树。

红黑树在各种框架,开源软件,系统中十分常见。比如在linux源代码中,就有使用红黑树做为容器管理进程的代码,再比如C++的STL中,Set, Map都是使用红黑树实现的。但是红黑树不光在教材里很少出现,即使在各类博客,教程也很少出现。我觉得这可能是因为红黑树的规则太复杂所导致的。

实际上,大家接下来会看到,我的讲解虽然看上去很啰嗦,很可怕,但在JDK里,红黑树的代码十分简洁。我们先看原理。

定义和性质

红黑树是一种自平衡二叉查找树。它的统计性能要好于平衡二叉树(AVL树),因此,红黑树在很多地方都有应用。在STL中,很多部分(目前包括set,multiset,map, multimap)应用了红黑树。它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(logn)时间内做查找,插入和删除等操作。

与二叉查找树相比,红黑树的树结点多了一个颜色属性,而每个结点不是黑色即是红色。这就是红黑树名称的由来。树的每个节点是一个五元组:color(颜色),key(数据), left(左孩子),right(右孩子)和parent(父结点)。注意哦,红黑树是一种平衡树,但是结点的结构却出奇的简单,比起传统二叉树,只多了颜色而已。

红黑树具有以下性质:根是黑色

所有叶子都是黑色(叶子是NIL结点)

如果一个结点是红的,则它的两个儿子都是黑的

从任一结点到其叶子的所有简单路径都包含相同数目的黑色结点

总结起来,最重要的就是红色结点不能有红色孩子,从根到任意叶子,经过的黑色结点数目相等。

插入数据

红黑树从根本上说还是排序二叉树,因此,红黑树的查找操作与二叉排序树的查找操作是一致的。

向红黑树中插入新的结点。具体做法是,将新结点的 color 赋为红色,然后以二叉排序树的插入方法插入到红黑树中去。之所以将新插入的结点的颜色赋为红色,是因为:如果设为黑色,就会导致根到叶子的路径上有一条路上,多一个额外的黑结点,这个是很难调整的。但是设为红色结点后,可能会导致出现两个连续红色结点的冲突,那么可以通过颜色调换和树旋转来调整,这样简单多了。

接下来,讨论一下插入以后,红黑树的情况。设要插入的结点为N,其父结点为P,其 祖父结点为G,其父亲的兄弟结点为U(即P和U 是同一个结点的两个子结点)。如果P是黑色的,则整棵树不必调整就已经满足了红黑树的所有性质。如果P是红色的(可知,其父结点G一定是黑色的),则插入N后,违背了红色结点只能有黑色孩子的性质,需要进行调整。

调整时分以下三种情况:

第一、N的叔叔U是红色的。将P和U重绘为黑色并重绘结点G为红色。现在新结点N有 了一个黑色的父结点P,因为通过父结点P或叔父结点U的任何路径都必定通过祖父结点G, 在这些路径上的黑结点数目没有改变。但是,红色的祖父结点G的父结点也有可能是红色 的,这就违反了性质3。为了解决这个问题,我们在祖父结点G递归向上调整颜色。如图2.14

第二、N的叔叔U是黑色的,且N是左孩子。对祖父结点G 的一次右旋转; 在旋转产生的树中,以前的父结点P现在是新结点N和以前的祖父节点 G 的父结点,然后交换以前的父结点P和祖父结点G的颜色,结果仍满足红黑树性质。如图 2.15。在(b)中,虚线代表原来的指针,实线代表旋转过后的指针。所谓旋转就是改变图中所示的两个指针的值即可。当然,在实际应用中,还有父指针p也需要修改,这里为了图示的简洁而省略掉了。

第三、N的叔叔U是黑色的,且N是右孩子。我们对P进行一次左旋转调换新结点和其父 结点的角色,就把问题转化成了第二种情况。如图 2.16所示。

红黑树插入数据的代码与二叉查找树是相同的,只是在插入以后,会对不满足红黑树性质的结点进行调整。具体的调整的代码如下所示。

代码中的 right rotate 的操作就是平衡二叉树中的右旋操作的函数。可见,红黑树的插入的调整的核心操作仍然是结点的旋转。所以深刻地理解旋转操作对于理解自平衡的二叉树具有重要意义。

好了。今天就讲这么多。今天的作业:

向树中依次插入(1,2,3,4,5,6,7,8,9,10),并且在纸上画出来红黑树变化的过程。总共画十幅图。拍成照片,发到我QQ上。

明天我们来讲红黑树的删除。后天讲代码。

上一节课:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一段Python实现的红黑树代码: ```python class Node: def __init__(self, val, color='red', left=None, right=None): self.val = val self.color = color self.left = left self.right = right class RedBlackTree: def __init__(self): self.root = None def insert(self, val): if not self.root: self.root = Node(val, 'black') else: node = self._insert(val, self.root) if node: self._fix_tree(node) def _insert(self, val, node): if val < node.val: if node.left: return self._insert(val, node.left) else: node.left = Node(val) return node.left elif val > node.val: if node.right: return self._insert(val, node.right) else: node.right = Node(val) return node.right def _fix_tree(self, node): while node != self.root and node.color != 'black' and node.parent.color == 'red': if node.parent == node.parent.parent.left: uncle = node.parent.parent.right if uncle and uncle.color == 'red': node.parent.color = 'black' uncle.color = 'black' node.parent.parent.color = 'red' node = node.parent.parent else: if node == node.parent.right: node = node.parent self._left_rotate(node) node.parent.color = 'black' node.parent.parent.color = 'red' self._right_rotate(node.parent.parent) else: uncle = node.parent.parent.left if uncle and uncle.color == 'red': node.parent.color = 'black' uncle.color = 'black' node.parent.parent.color = 'red' node = node.parent.parent else: if node == node.parent.left: node = node.parent self._right_rotate(node) node.parent.color = 'black' node.parent.parent.color = 'red' self._left_rotate(node.parent.parent) self.root.color = 'black' def _left_rotate(self, node): temp = node.right node.right = temp.left if temp.left: temp.left.parent = node temp.parent = node.parent if not node.parent: self.root = temp elif node == node.parent.left: node.parent.left = temp else: node.parent.right = temp temp.left = node node.parent = temp def _right_rotate(self, node): temp = node.left node.left = temp.right if temp.right: temp.right.parent = node temp.parent = node.parent if not node.parent: self.root = temp elif node == node.parent.right: node.parent.right = temp else: node.parent.left = temp temp.right = node node.parent = temp def in_order_traversal(self, node): if not node: return self.in_order_traversal(node.left) print(node.val, end=' ') self.in_order_traversal(node.right) tree = RedBlackTree() tree.insert(10) tree.insert(20) tree.insert(30) tree.insert(100) tree.insert(90) tree.insert(70) tree.insert(40) tree.in_order_traversal(tree.root) ``` 这段代码实现了红黑树插入和左右旋转操作,并且在插入节点后通过_fix_tree()方法来保持红黑树的平衡。其中,节点颜色为红色或黑色,红色节点的父节点必须为黑色,而红色节点的子节点必须为黑色或空节点。这个平衡性质使得红黑树的查找、插入和删除操作的时间复杂度均为O(log n)。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值