linux内核的红黑树

很多博文都介绍过红黑树,linux内核对红黑树的实现无疑是经典中的经典,那么就来看看这经典中的经典是怎么样的。

1. 回忆树的基本知识

什么是树,有很多博文中会罗列几条规则,满足那几条规则的数据结构就称为树,这种定义方式是很数学化的表达方式。这里抓出来两条最重要的规则:

1)树的节点有且仅有一个父节点;
2)任何非页节点都可以分为若干不相交的子树。
其实这两条规则都是表述同一个含义,就是树是不相交的,节点之间不能构成回环。
常用到的是二叉树,二叉树对节点孩子的个数进行了约束,即节点的孩子个数不超过两个。二叉树的一个重要应用是排序与查找,所以就有了排序二叉树或者说查找二叉树。排序二叉树的左子树的节点的值都小于根节点,右子树的的节点的值都大于根节点。在红黑树的左旋和右旋操作中要用到该性质,下图所示,即为一个左旋转。问题是为什么D可以作为A的右孩子,因为D总是比A大的,这就是二叉树性质的运用。

#mermaid-svg-oBq8YyP6JXipUyop .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-oBq8YyP6JXipUyop .label text{fill:#333}#mermaid-svg-oBq8YyP6JXipUyop .node rect,#mermaid-svg-oBq8YyP6JXipUyop .node circle,#mermaid-svg-oBq8YyP6JXipUyop .node ellipse,#mermaid-svg-oBq8YyP6JXipUyop .node polygon,#mermaid-svg-oBq8YyP6JXipUyop .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-oBq8YyP6JXipUyop .node .label{text-align:center;fill:#333}#mermaid-svg-oBq8YyP6JXipUyop .node.clickable{cursor:pointer}#mermaid-svg-oBq8YyP6JXipUyop .arrowheadPath{fill:#333}#mermaid-svg-oBq8YyP6JXipUyop .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-oBq8YyP6JXipUyop .flowchart-link{stroke:#333;fill:none}#mermaid-svg-oBq8YyP6JXipUyop .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-oBq8YyP6JXipUyop .edgeLabel rect{opacity:0.9}#mermaid-svg-oBq8YyP6JXipUyop .edgeLabel span{color:#333}#mermaid-svg-oBq8YyP6JXipUyop .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-oBq8YyP6JXipUyop .cluster text{fill:#333}#mermaid-svg-oBq8YyP6JXipUyop div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-oBq8YyP6JXipUyop .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-oBq8YyP6JXipUyop text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-oBq8YyP6JXipUyop .actor-line{stroke:grey}#mermaid-svg-oBq8YyP6JXipUyop .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-oBq8YyP6JXipUyop .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-oBq8YyP6JXipUyop #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-oBq8YyP6JXipUyop .sequenceNumber{fill:#fff}#mermaid-svg-oBq8YyP6JXipUyop #sequencenumber{fill:#333}#mermaid-svg-oBq8YyP6JXipUyop #crosshead path{fill:#333;stroke:#333}#mermaid-svg-oBq8YyP6JXipUyop .messageText{fill:#333;stroke:#333}#mermaid-svg-oBq8YyP6JXipUyop .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-oBq8YyP6JXipUyop .labelText,#mermaid-svg-oBq8YyP6JXipUyop .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-oBq8YyP6JXipUyop .loopText,#mermaid-svg-oBq8YyP6JXipUyop .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-oBq8YyP6JXipUyop .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-oBq8YyP6JXipUyop .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-oBq8YyP6JXipUyop .noteText,#mermaid-svg-oBq8YyP6JXipUyop .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-oBq8YyP6JXipUyop .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-oBq8YyP6JXipUyop .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-oBq8YyP6JXipUyop .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-oBq8YyP6JXipUyop .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-oBq8YyP6JXipUyop .section{stroke:none;opacity:0.2}#mermaid-svg-oBq8YyP6JXipUyop .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-oBq8YyP6JXipUyop .section2{fill:#fff400}#mermaid-svg-oBq8YyP6JXipUyop .section1,#mermaid-svg-oBq8YyP6JXipUyop .section3{fill:#fff;opacity:0.2}#mermaid-svg-oBq8YyP6JXipUyop .sectionTitle0{fill:#333}#mermaid-svg-oBq8YyP6JXipUyop .sectionTitle1{fill:#333}#mermaid-svg-oBq8YyP6JXipUyop .sectionTitle2{fill:#333}#mermaid-svg-oBq8YyP6JXipUyop .sectionTitle3{fill:#333}#mermaid-svg-oBq8YyP6JXipUyop .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-oBq8YyP6JXipUyop .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-oBq8YyP6JXipUyop .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-oBq8YyP6JXipUyop .grid path{stroke-width:0}#mermaid-svg-oBq8YyP6JXipUyop .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-oBq8YyP6JXipUyop .task{stroke-width:2}#mermaid-svg-oBq8YyP6JXipUyop .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-oBq8YyP6JXipUyop .taskText:not([font-size]){font-size:11px}#mermaid-svg-oBq8YyP6JXipUyop .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-oBq8YyP6JXipUyop .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-oBq8YyP6JXipUyop .task.clickable{cursor:pointer}#mermaid-svg-oBq8YyP6JXipUyop .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-oBq8YyP6JXipUyop .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-oBq8YyP6JXipUyop .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-oBq8YyP6JXipUyop .taskText0,#mermaid-svg-oBq8YyP6JXipUyop .taskText1,#mermaid-svg-oBq8YyP6JXipUyop .taskText2,#mermaid-svg-oBq8YyP6JXipUyop .taskText3{fill:#fff}#mermaid-svg-oBq8YyP6JXipUyop .task0,#mermaid-svg-oBq8YyP6JXipUyop .task1,#mermaid-svg-oBq8YyP6JXipUyop .task2,#mermaid-svg-oBq8YyP6JXipUyop .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-oBq8YyP6JXipUyop .taskTextOutside0,#mermaid-svg-oBq8YyP6JXipUyop .taskTextOutside2{fill:#000}#mermaid-svg-oBq8YyP6JXipUyop .taskTextOutside1,#mermaid-svg-oBq8YyP6JXipUyop .taskTextOutside3{fill:#000}#mermaid-svg-oBq8YyP6JXipUyop .active0,#mermaid-svg-oBq8YyP6JXipUyop .active1,#mermaid-svg-oBq8YyP6JXipUyop .active2,#mermaid-svg-oBq8YyP6JXipUyop .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-oBq8YyP6JXipUyop .activeText0,#mermaid-svg-oBq8YyP6JXipUyop .activeText1,#mermaid-svg-oBq8YyP6JXipUyop .activeText2,#mermaid-svg-oBq8YyP6JXipUyop .activeText3{fill:#000 !important}#mermaid-svg-oBq8YyP6JXipUyop .done0,#mermaid-svg-oBq8YyP6JXipUyop .done1,#mermaid-svg-oBq8YyP6JXipUyop .done2,#mermaid-svg-oBq8YyP6JXipUyop .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-oBq8YyP6JXipUyop .doneText0,#mermaid-svg-oBq8YyP6JXipUyop .doneText1,#mermaid-svg-oBq8YyP6JXipUyop .doneText2,#mermaid-svg-oBq8YyP6JXipUyop .doneText3{fill:#000 !important}#mermaid-svg-oBq8YyP6JXipUyop .crit0,#mermaid-svg-oBq8YyP6JXipUyop .crit1,#mermaid-svg-oBq8YyP6JXipUyop .crit2,#mermaid-svg-oBq8YyP6JXipUyop .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-oBq8YyP6JXipUyop .activeCrit0,#mermaid-svg-oBq8YyP6JXipUyop .activeCrit1,#mermaid-svg-oBq8YyP6JXipUyop .activeCrit2,#mermaid-svg-oBq8YyP6JXipUyop .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-oBq8YyP6JXipUyop .doneCrit0,#mermaid-svg-oBq8YyP6JXipUyop .doneCrit1,#mermaid-svg-oBq8YyP6JXipUyop .doneCrit2,#mermaid-svg-oBq8YyP6JXipUyop .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-oBq8YyP6JXipUyop .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-oBq8YyP6JXipUyop .milestoneText{font-style:italic}#mermaid-svg-oBq8YyP6JXipUyop .doneCritText0,#mermaid-svg-oBq8YyP6JXipUyop .doneCritText1,#mermaid-svg-oBq8YyP6JXipUyop .doneCritText2,#mermaid-svg-oBq8YyP6JXipUyop .doneCritText3{fill:#000 !important}#mermaid-svg-oBq8YyP6JXipUyop .activeCritText0,#mermaid-svg-oBq8YyP6JXipUyop .activeCritText1,#mermaid-svg-oBq8YyP6JXipUyop .activeCritText2,#mermaid-svg-oBq8YyP6JXipUyop .activeCritText3{fill:#000 !important}#mermaid-svg-oBq8YyP6JXipUyop .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-oBq8YyP6JXipUyop g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-oBq8YyP6JXipUyop g.classGroup text .title{font-weight:bolder}#mermaid-svg-oBq8YyP6JXipUyop g.clickable{cursor:pointer}#mermaid-svg-oBq8YyP6JXipUyop g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-oBq8YyP6JXipUyop g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-oBq8YyP6JXipUyop .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-oBq8YyP6JXipUyop .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-oBq8YyP6JXipUyop .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-oBq8YyP6JXipUyop .dashed-line{stroke-dasharray:3}#mermaid-svg-oBq8YyP6JXipUyop #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-oBq8YyP6JXipUyop #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-oBq8YyP6JXipUyop #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-oBq8YyP6JXipUyop #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-oBq8YyP6JXipUyop #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-oBq8YyP6JXipUyop #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-oBq8YyP6JXipUyop #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-oBq8YyP6JXipUyop #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-oBq8YyP6JXipUyop .commit-id,#mermaid-svg-oBq8YyP6JXipUyop .commit-msg,#mermaid-svg-oBq8YyP6JXipUyop .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-oBq8YyP6JXipUyop .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-oBq8YyP6JXipUyop .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-oBq8YyP6JXipUyop g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-oBq8YyP6JXipUyop g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-oBq8YyP6JXipUyop g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-oBq8YyP6JXipUyop g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-oBq8YyP6JXipUyop g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-oBq8YyP6JXipUyop g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-oBq8YyP6JXipUyop .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-oBq8YyP6JXipUyop .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-oBq8YyP6JXipUyop .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-oBq8YyP6JXipUyop .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-oBq8YyP6JXipUyop .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-oBq8YyP6JXipUyop .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-oBq8YyP6JXipUyop .edgeLabel text{fill:#333}#mermaid-svg-oBq8YyP6JXipUyop .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-oBq8YyP6JXipUyop .node circle.state-start{fill:black;stroke:black}#mermaid-svg-oBq8YyP6JXipUyop .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-oBq8YyP6JXipUyop #statediagram-barbEnd{fill:#9370db}#mermaid-svg-oBq8YyP6JXipUyop .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-oBq8YyP6JXipUyop .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-oBq8YyP6JXipUyop .statediagram-state .divider{stroke:#9370db}#mermaid-svg-oBq8YyP6JXipUyop .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-oBq8YyP6JXipUyop .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-oBq8YyP6JXipUyop .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-oBq8YyP6JXipUyop .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-oBq8YyP6JXipUyop .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-oBq8YyP6JXipUyop .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-oBq8YyP6JXipUyop .note-edge{stroke-dasharray:5}#mermaid-svg-oBq8YyP6JXipUyop .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-oBq8YyP6JXipUyop .error-icon{fill:#522}#mermaid-svg-oBq8YyP6JXipUyop .error-text{fill:#522;stroke:#522}#mermaid-svg-oBq8YyP6JXipUyop .edge-thickness-normal{stroke-width:2px}#mermaid-svg-oBq8YyP6JXipUyop .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-oBq8YyP6JXipUyop .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-oBq8YyP6JXipUyop .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-oBq8YyP6JXipUyop .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-oBq8YyP6JXipUyop .marker{fill:#333}#mermaid-svg-oBq8YyP6JXipUyop .marker.cross{stroke:#333}:root { --mermaid-font-family: "trebuchet ms", verdana, arial;} #mermaid-svg-oBq8YyP6JXipUyop {color: rgba(0, 0, 0, 0.75);font: ;}

旋转前
旋转后
B
A
C
D
E
A
C
E
B
D

图1 二叉树性质的运用
二叉树在不幸的时候会退化为链表结构,为了这个有了平衡二叉树,红黑树就是我们常用的平衡二叉树之一。是的,今天的主角就是红黑树。

2. 什么是红黑树

linux源码(linux 5.13)中对红黑树的定义是如下的描述,那么黑节点的孩子可以为黑吗?这是完全有可能的。

1) A node is either red or black
2) The root is black //根节点为黑
3) All leaves (NULL) are black //所有的叶节点为黑
4) Both children of every red node are black //所有红节点的孩子为黑
5) Every simple path from root to leaves contains the same numberof black nodes.

3. linux源码中红黑树的实现

我们从使用者的角度来看红黑树是如何实现的。在linux中,双向链表、哈希链表、红黑树的实现都有一个共同点,那就是数据结构只用于连接,而不存放数据。需要使用这些连接的数据结构,其中必须包含相应连接的成员。不论是链表还是树,都有根节点。红黑树的根节点,就是一个指向节点的指针。

struct rb_root {struct rb_node *rb_node;
};
struct rb_node {unsigned long  __rb_parent_color;struct rb_node *rb_right;struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));//最低的4位始终为0,可作其它用途

定义一个树的根节点使用宏RB_ROOT,rb_node指针被初始化为NULL。RB_ROOT返回的是一个rb_root实例,由于one_tree是数组,所以右边需要加花括号。one_tree是数组名,是用于赋值给指针。root_tree就是指向红黑树根节点的指针,当有很多红黑树时,只需把root_tree当做一个数组看待。

struct rb_root one_tree[1] = { RB_ROOT };
struct rb_root *root_tree = one_tree;

在红黑树中查找的样例如下所示,linux内核并没有采用提供回调函数的方式让使用者直接使用,而是需要开发者自己定义。在如下的流程中,开发者可以改变比较大小的方式,还可以根据需要增加一些其它的处理流程。红黑树的查找与普通的二叉排序树并没有区别。

struct mytype *my_search(struct rb_root *root, char *string){struct rb_node *node = root->rb_node; //rb_node是一个指针while (node) {//参数的第三个参数node是结构体mytype中的成员名称struct mytype *data = container_of(node, struct mytype, node);int result;result = strcmp(string, data->keystring);if (result < 0)node = node->rb_left;else if (result > 0)node = node->rb_right;elsereturn data;}return NULL;}

有差别的是在红黑树中插入节点。与查找不同,一开始定义的指针new是一个指向根节点的指针的指针。*new的含义即是指向节点的指针。为什么要用指向指针的指针呢?目的是为了在通过函数传参时能修改指针的值。rb_link_node将data->node中的数据成员进行了修改,__rb_parent_color的颜色修改为其父节点的颜色,左孩子和右孩子都设置为NULL,并将new指针指向node指针。那么new指针的含义是什么,它可能是左孩子,也可能是右孩子,更确切的含义是当前节点要插入的位置。

int my_insert(struct rb_root *root, struct mytype *data){struct rb_node **new = &(root->rb_node), *parent = NULL;/* Figure out where to put new node */while (*new) {struct mytype *this = container_of(*new, struct mytype, node);int result = strcmp(data->keystring, this->keystring);parent = *new;if (result < 0)new = &((*new)->rb_left);else if (result > 0)new = &((*new)->rb_right);elsereturn FALSE;}/* Add new node and rebalance tree. */rb_link_node(&data->node, parent, new);rb_insert_color(&data->node, root);return TRUE;}

rb_insert_color函数是红黑树相对于普通二叉排序树最大的差别。这个函数中平衡二叉树的方式主要有3种:a)改变颜色,0表示red,1表示black。对于对齐的节点,低4位总是0,所以默认的情况下是红色的节点。那么对于父节点是black的情况,直接插入即可,无需改变颜色。如果父节点是红色则需要改变颜色。b)左旋转,将一个节点的右孩子变为父节点,节点本身变为左孩子。c)右旋转,将一个节点的做孩子变为父节点,节点本身变为右孩子。

static __always_inline void
__rb_insert(struct rb_node *node, struct rb_root *root,void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
{// 节点在没有上色之前__rb_parent_color表示指向父节点的指针,且低位未被标记struct rb_node *parent = rb_red_parent(node), *gparent, *tmp;while (true) {/** Loop invariant: node is red.*/if (unlikely(!parent)) {/** The inserted node is root. Either this is the* first node, or we recursed at Case 1 below and* are no longer violating 4).*/// 根节点直接设置为黑色,1表示黑色,__rb_parent_color被设置为1.// 因为根节点没有父节点,所以第二个参数为NULLrb_set_parent_color(node, NULL, RB_BLACK);break;}/** If there is a black parent, we are done.* Otherwise, take some corrective action as,* per 4), we don't want a red root or two* consecutive red nodes.*/// 父节点为黑色,无需做任何处理,颜色呢?if(rb_is_black(parent))break;// 父节点为红色才能走到此处为红色意味着低位为0.gparent = rb_red_parent(parent);tmp = gparent->rb_right;if (parent != tmp) {    /* parent == gparent->rb_left */if (tmp && rb_is_red(tmp)) {// 父节点存在兄弟/** Case 1 - node's uncle is red (color flips).**       G            g*      / \          / \*     p   u  -->   P   U*    /            /*   n            n** However, since g's parent might be red, and* 4) does not allow this, we need to recurse* at g.*/// 父节点及其兄弟的parent都设置为黑,parent和兄弟不能直接访问其父节点了rb_set_parent_color(tmp, gparent, RB_BLACK);rb_set_parent_color(parent, gparent, RB_BLACK);node = gparent;parent = rb_parent(node);//最低两位被设为0,parent已经被设置为祖父的parentrb_set_parent_color(node, parent, RB_RED);continue;}tmp = parent->rb_right;if (node == tmp) {/** Case 2 - node's uncle is black and node is* the parent's right child (left rotate at parent).**      G             G*     / \           / \*    p   U  -->    n   U*     \           /*      n         p** This still leaves us in violation of 4), the* continuation into Case 3 will fix that.*/tmp = node->rb_left;WRITE_ONCE(parent->rb_right, tmp);WRITE_ONCE(node->rb_left, parent);if (tmp)rb_set_parent_color(tmp, parent,RB_BLACK);rb_set_parent_color(parent, node, RB_RED);augment_rotate(parent, node);parent = node;tmp = node->rb_right;}/** Case 3 - node's uncle is black and node is* the parent's left child (right rotate at gparent).**        G           P*       / \         / \*      p   U  -->  n   g*     /                 \*    n                   U*/WRITE_ONCE(gparent->rb_left, tmp); /* == parent->rb_right */WRITE_ONCE(parent->rb_right, gparent);if (tmp)rb_set_parent_color(tmp, gparent, RB_BLACK);__rb_rotate_set_parents(gparent, parent, root, RB_RED);augment_rotate(gparent, parent);break;} else {tmp = gparent->rb_left;if (tmp && rb_is_red(tmp)) {/* Case 1 - color flips */rb_set_parent_color(tmp, gparent, RB_BLACK);rb_set_parent_color(parent, gparent, RB_BLACK);node = gparent;parent = rb_parent(node);rb_set_parent_color(node, parent, RB_RED);continue;}tmp = parent->rb_left;if (node == tmp) {/* Case 2 - right rotate at parent */tmp = node->rb_right;// 非锁的方式读时确保不是致命的WRITE_ONCE(parent->rb_left, tmp);WRITE_ONCE(node->rb_right, parent);if (tmp)rb_set_parent_color(tmp, parent,RB_BLACK);rb_set_parent_color(parent, node, RB_RED);augment_rotate(parent, node);parent = node;tmp = node->rb_left;}/* Case 3 - left rotate at gparent */WRITE_ONCE(gparent->rb_right, tmp); /* == parent->rb_left */WRITE_ONCE(parent->rb_left, gparent);if (tmp)rb_set_parent_color(tmp, gparent, RB_BLACK);__rb_rotate_set_parents(gparent, parent, root, RB_RED);augment_rotate(gparent, parent);break;}}
}

linux内核的红黑树相关推荐

  1. Linux内核的红黑树源码实现以及调用

    红黑树可以说是程序员经常遇到的一种数据结构,不管是工作还是面试都会涉及,有时候还会让你写一段红黑树代码. 本文主要是讲Linux中的红黑树,关于红黑树定义参考wiki:https://en.wikip ...

  2. linux算法设计,红黑树的原理分析和算法设计

    红黑树是60年代中期计算机科学界找寻一种算法复杂度稳定,容易实现的数据存储算法的产物.在优先级队列.字典等实用领域都有广泛地应用,更是70年代提出的关系数据库模型--B树的鼻祖.在Linux kern ...

  3. 红黑树分为红和黑有什么好处_彻底搞懂红黑树

    红黑树和c++ 虚拟继承内存分布 几乎成了我的死敌,因为完全没用过,所以导致每次看懂了之后都忘了(也许不是真的看懂了,有些关键性的东西没理解透),这次准备把这两个难题(其实也不难)仔细看懂,然后再写一 ...

  4. Linux内核设计与实现——内核数据结构

    主要内容 链表 队列 映射 二叉树 1. 链表 单向链表.双向链表 环形链表 linux内核中的链表使用方法和一般数据结构中定义的链表是有所不同的. 传统链表: 传统双向链表.png 传统的链表有个最 ...

  5. 内核数据结构之红黑树

    红黑树是一种自平衡的二叉查找树,是Linux主要的二叉树结构.红黑树有一个特殊的颜色属性,要么红色,要么黑色.红黑树通过强制以下条件来保证红黑树仍然是半平衡的. 所有结点要是红色或黑色的. 叶子结点是 ...

  6. 不是linux内核的国产系统,红芯浏览器不算自主内核,但会被国产操作系统所预装...

    红芯浏览器算不算是自主内核的浏览器?正确答案:不是.因为红芯浏览器内核(Redcore)是基于Chromium的,既然是基于其它内核就不能算是自主内核.但是红芯国产浏览器会被国产操作系统所预装,因为麒 ...

  7. linux内核中的数据结构

    http://vinllen.com/linuxnei-he-zhong-de-shu-ju-jie-gou/ https://zhuanlan.zhihu.com/p/58087261 https: ...

  8. 《Linux内核设计与实现》 第八周读书笔记 第四章 进程调度

    20135307 张嘉琪 第八周读书笔记 第四章 进程调度 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间,进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统.只有 ...

  9. Linux内核常用数据结构

    Linux中最重要最常用如下四种: LIST:链表 <linux/list.h> Linux内核的标准链表就是采用"环形.双向"链表形式实现 沿着链表移动智能是线性移动 ...

最新文章

  1. leetcode-155 最小栈
  2. String 堆内存和栈内存
  3. Java B2B2C多用户商城 springcloud架构- 企业云架构common-service代码结构分析(六)...
  4. python中的栈结构_Python可以实现栈的结构吗
  5. 合并k个有序链表 python_leetcode第23题-合并K个有序链表
  6. LeetCode刷题(27)
  7. java 获取 classpath下的配置文件
  8. weblogic中删除自动部署项目
  9. Java入门第37课——猜字母游戏之设计数据结构
  10. 令人赞叹的 MySQL
  11. 献给自己技术成长的第一年
  12. 「业务架构」商业模式画布
  13. JS jeDate日期控件使用
  14. 电脑上怎么批量压缩图片?如何快速批量压缩图片?
  15. 再战中原之地图编辑器
  16. RF自动化测试框架(二)
  17. 无法打开U盘中的虚拟机
  18. 春夜宴从弟桃花园序 ——李白
  19. 赛门铁克为 Google 域名颁发证书
  20. java小游戏贪吃蛇

热门文章

  1. 帕斯卡三角形html,数学之美:杨辉三角(帕斯卡三角)的奇特性质
  2. 江西省九江市谷歌高清卫星地图下载
  3. 计算机二级考试不及格看不到分数吗,计算机二级查不到成绩是不是没过,不及格有分数吗...
  4. hbase查看表结构_HBase简介和基本命令
  5. android 海拔高度_Android:如何获取准确的海拔高度?
  6. 归并排序详解(递归+非递归)
  7. 归并排序(递归,非递归)
  8. 拥有10年编程经验的你,为什么还一直停留在原地
  9. android定义颜色数组,android – 我如何保存在array.xml中的颜色,并让它回到Color []数组...
  10. 让iis支持二级域名泛解析