操作系统在实现调度的时候会使用rb-tree,可见红黑树对于操作系统而言是多么的重要,本文首先介绍一下rb-tree的基本要素,后面连载逐渐了解rb-tree
对于一个树的结构,默认的实现应该如下
struct Node { struct Node *left; /* left element */ struct Node *right; /* right element */ }
这里通过Node就是树的节点,left是树的左子树,right是树的右子树
此时我们新增一个parent的Node指针,这样我们可以查找树里面的元素就无需每次从根节点遍历,结构体如下
struct Node { struct Node *left; /* left element */ struct Node *right; /* right element */ struct Node *parent; /* parent element */ }
对于红黑树,我们需要对Node添加颜色标识,可以如下
struct Node { struct Node *left; /* left element */ struct Node *right; /* right element */ struct Node *parent; /* parent element */ int rbe_color; /* node color */ }
这样,我们基本的红黑树的数据结构就完成了,接下来说明红黑树的特性
对于红黑树的基本特性,主要是如下四点
这里以 Data Structure Visualizations 网站绘图
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
下面展示一个从1-10共10个元素的红黑树图
可以发现:
红黑树的操作主要是左旋和右旋,以及插入和删除和搜索和染色,本文仅讨论左旋和右旋基本操作,插入,删除,搜索,染色等操作后面文章详细介绍。
关于左旋和右旋操作,是在红黑树出现不平衡的情况下,主动通过左旋和右旋调整使得整个红黑树平衡
对于左旋,就是红黑树不平衡的时候,对不平衡的节点向左旋转
假设有节点 x,y,a,b,r, 对其进行围绕x的左旋,如下所示
那么其具体步骤如下
简单理解就是,基于谁的节点左旋,就是将那个节点的右节点作为自己的父节点,然后重建叶子节点
为了更清楚的了解左旋步骤,我基于最上面10个元素的示例演示,先删除了节点8,则此时的树结构如下
此时因为节点7没有左孩子,但是节点10有左孩子,这并不平衡,所以需要对节点10进行右旋,右旋我们还没解释,简单理解就是将自己的左孩子作为自己的父亲。所以右旋后结构如下
我们发现节点9不平衡,其左孩子的黑色个数是3,而其他个数是4,所以将其染色如下
现在重点来了,但是此时节点7的左孩子是空,也就是其黑色节点数是3,我们需要左旋,步骤如下:
这样左旋完成之后,结果如下
此时还是黑色个数不对,我们将节点10染色成黑色即可。如下
我们介绍了左旋,对于右旋,就是红黑树不平衡的时候,对不平衡的节点向右旋转
假设有节点 x,y,a,b,r, 对齐进行围绕x的右旋,如下所示
那么其具体步骤如下
简单理解就是,基于谁的节点右旋,就是将那个节点的左节点作为自己的父节点,然后重建叶子节点
还是为了示例,还是基于上图删掉节点8之后的红黑树,此时我删除节点6,这里节点5会取代节点6,如下
此时红黑树在节点4上不平衡了,我们需要针对节点4进行右旋
步骤如下:
这样右旋完成之后,结果如下
最后发现节点2的黑色节点不平衡,个数不对,所以将节点1染色成黑色即可完成,如下
本文作为红黑树介绍的开头,简单介绍了红黑树的基础,例如红黑树的特性,红黑树的左旋和右旋操作。