Implementation of red-black tree algorithm in Linux kernel _unix Linux

Source: Internet
Author: User
Tags define null

First, Introduction

Balanced binary tree (balancedbinary or height-balanced)

Also known as the AVL tree. It is either an empty tree or a two-fork tree with the following properties: Its Saozi right subtree is a balanced binary tree, and the Saozi of the depth of the right subtree does not exceed 1. If the balance factor BF (Balancefactor) of the node in the two-fork tree is defined as the depth of the left subtree of the node minus the depth of its right subtree, the balance factor of all nodes in the balanced binary tree may be only-1, 0, and 1. (This section defines the data structure (C language Edition) from Min)

Red and black Trees

R-b Tree, the full name is Red-black tree, also known as the "red and black Trees", it is a special two-fork find trees. Each node of the red-black tree has a storage bit that indicates the color of the node, either red or black.

A red-black tree is a two-fork lookup tree that needs to maintain a balance when inserting or deleting a node, and each node has a color attribute:

(1), a node is either red or black.

(2), the root node is black.

(3) If a node is red, then its sub nodes must be black, which means that there will be no two consecutive red nodes along any path starting from the root node.

(4), each path from a node to a null pointer must contain the same number of black nodes.

The Linux kernel red-black tree algorithm is defined in the linux-2.6.38.8/include/linux/rbtree.h and linux-2.6.38.8/lib/rbtree.c two files.

Second, the structure body

struct Rb_node 
{ 
  unsigned long rb_parent_color; 
#define RB_RED   0 
#define Rb_black  1 
  struct rb_node *rb_right; 
  struct Rb_node *rb_left; 

The tricky part here is to use members rb_parent_color to store two kinds of data at the same time, one is the address of the parent node and the other is the coloring of the node. __attribute__((aligned(sizeof(long))))property ensures that the first address of each node in the red-black tree is 32-bit aligned (on a 32-bit machine), that is, the first address of each node bit[1] bit[0] is 0, so you can use bit[0 to store the color properties of the node without interfering with the storage of the parent node's first address.

rb_parent_colorfunction of the action:

#define Rb_parent (R)  (struct Rb_node *) ((r)->rb_parent_color & ~3)//Obtain the first address of its parent node 
#define RB_COLOR (R)  (R)->rb_parent_color & 1)//Get Color Properties #define RB_IS_RED (R)  (!rb_color (R))  //Determine if the color attribute is red 
# Define Rb_is_black (R) Rb_color (r)//to determine if the color property is black 
#define RB_SET_RED (R) do {(R)->rb_parent_color &= ~} while ( 0//Set red property 
#define Rb_set_black (R) do {(R)->rb_parent_color |= 1;} while (0)//Set black property 
 
static inline void RB _set_parent (struct rb_node *rb, struct rb_node *p)//Set the function of the first address of its parent node 
{ 
  Rb->rb_parent_color = (rb->rb_ Parent_color & 3) | (unsigned long) p; 
} 
static inline void Rb_set_color (struct rb_node *rb, int color)//Set the function of the node color property 
{ 
  Rb->rb_parent_color = (rb-& Gt;rb_parent_color & ~) | Color 

Initialize new node:

static inline void Rb_link_node (struct rb_node * node, struct Rb_node * parent, 
        struct Rb_node * * rb_link) 
{ 
  n Ode->rb_parent_color = (unsigned long) parent;  Sets the first address of its parent node (the parent node of the root node is null), and the Color property is set to black 
  node->rb_left = Node->rb_right = NULL;  Initializes the left and right subtree of the new node 
 
  *rb_link = node;//point to new node 

Pointer to red-black root node:

struct Rb_root 
{ 
  struct rb_node *rb_node; 
}; 
 
 
#define RB_ROOT (struct rb_root) {NULL,}//Initialize pointer to red-black root node 
#define Rb_entry (PTR, type, member) container_of (PTR, Typ E, member)//To obtain the first address of the structure containing the struct Rb_node 
 
#define Rb_empty_root (Root) ((root)->rb_node = = null)//To determine whether the tree is empty 
#define RB_EMPTY_NODE (node) (node = = node)//Determine whether the parent node of node is itself (Rb_parent) 

Third, insert

First insert a new node like a binary lookup tree, and then adjust accordingly so that it satisfies the color attributes of the red and black tree (the essence is to maintain the balance of the red and black tree).

rb_insert_colorthe function uses a while loop to constantly determine whether the parent node exists and the color attribute is red.

If the judgment condition is true, it is divided into two parts to perform the following actions:

(1) When the parent node is the root of the left subtree of the grandparent node:

A, there is Uncle's knot, and the color attribute is red.

B, when node is the root of the right subtree of its parent node, it is left, and then step c is performed.

C, when node is the root of the left subtree of its parent node.

(2) When the parent node is the root of the right subtree of the grandparent node, the operation is roughly the same as in step (1), which is not discussed here.

If False, the color property of the root node is always set to black.

void Rb_insert_color (struct rb_node *node, struct rb_root *root) {struct Rb_node *parent, *gparent; while (parent = rb_parent (node) && rb_is_red (parent))//parent node is not NULL, and the color attribute is red {gparent = Rb_parent (Parent ); Get the Grandparent node if (parent = = Gparent->rb_left)//parent node is the root of the left subtree of the grandparent node {{Register struct Rb_node *uncl E = gparent->rb_right; Get Uncle node if (Uncle && rb_is_red (uncle))//Uncle node exists, and the color attribute is red {rb_set_black (uncle);//Set Uncle Knot for Black rb_set_black (parent); Setting the parent node to be black rb_set_red (gparent); Set grandparent node to red node = gparent; Node points to grandfather node continue; Continue the next while loop} if (Parent->rb_right = node)//When node is the root of the right subtree of its parent node {Registe 
        R struct Rb_node *tmp; __rb_rotate_left (parent, root); L-tmp = parent; 
        Adjusts the parent and node pointers to parent = node; 
      node = tmp; } rb_set_black (parent); 
  Set parent node to black    Rb_set_red (gparent); Set grandparent node to red __rb_rotate_right (gparent, Root); Turn right} else {//! ( 
        Parent = = gparent->rb_left) {Register struct Rb_node *uncle = gparent->rb_left; 
          if (Uncle && rb_is_red (uncle)) {rb_set_black (uncle); 
          Rb_set_black (parent); 
          Rb_set_red (gparent); 
          node = gparent; 
        Continue 
        } if (Parent->rb_left = node) {register struct rb_node *tmp; 
        __rb_rotate_right (parent, root); 
        TMP = parent; 
        parent = node; 
      node = tmp; 
      } rb_set_black (parent); 
      Rb_set_red (gparent); 
    __rb_rotate_left (gparent, Root); 
 
  //end if (parent = = gparent->rb_left)}//end while (parent = rb_parent (node) && rb_is_red (parent)) 
Rb_set_black (Root->rb_node);  }

IV. Delete

Like a binary lookup tree deletion, you first need to find the node you want to delete, and then divide it into three different scenarios according to the node's left and right subtree:

If node the color attribute of the node is black, you need __rb_erase_color to call the function to adjust it.

void Rb_erase (struct rb_node *node, struct rb_root *root) {struct Rb_node *child, *parent; 
 
  int color; 
  if (!node->rb_left)//delete node no left subtree child = node->rb_right; 
  else if (!node->rb_right)//delete node no right subtree child = node->rb_left; 
 
    else//left and right subtrees have {struct Rb_node *old = node, *left; 
    node = node->rb_right; 
 
    while (left = node->rb_left)!= NULL) node = left; 
      if (rb_parent) {if (Rb_parent (old)->rb_left = = old) rb_parent (old)->rb_left = node; 
    else rb_parent (old)->rb_right = node; 
 
    else Root->rb_node = node; 
    Child = node->rb_right; 
    Parent = rb_parent (node); 
 
    color = rb_color (node); 
    if (parent = = old) {parent = node; 
      else {if (child) rb_set_parent (child, parent); 
 
      Parent->rb_left = child; 
      Node->rb_right = old->rb_right; 
    Rb_set_parent (old->rb_right, node); } node->rb_parent_color = old->rb_parent_color; 
    Node->rb_left = old->rb_left; 
 
    Rb_set_parent (old->rb_left, node); 
  Goto color; }//end Else parent = rb_parent (node); Gets the parent node of the delete node color = rb_color (node); 
  Gets the color attribute of the Delete node if (child) rb_set_parent (child, parent); 
    if (parent) {if (Parent->rb_left = node) parent->rb_left = child; 
  else parent->rb_right = child; 
 
 else Root->rb_node = child; 
Color:if (color = = rb_black)//If the color attribute of the deleted node is black, the __rb_erase_color function must be invoked to adjust __rb_erase_color (child, parent, root);  }

Five, traverse

rb_firstand rb_next functions can form a sequence traversal, that is, to traverse all nodes in the red-black tree in ascending order.

struct Rb_node *rb_first (const struct rb_root *root) {struct rb_node; 
  n = root->rb_node; 
  if (!n) return NULL; 
  while (n->rb_left) n = n->rb_left; 
return n; 
 
  } struct Rb_node *rb_next (const struct Rb_node *node) {struct rb_node; 
 
  if (rb_parent (node) = node) return NULL; /* If We have a right-hand child, go down and then left as we can.  
    */if (node->rb_right) {node = node->rb_right; 
    while (Node->rb_left) node=node->rb_left; 
  return (struct Rb_node *) node; }/* No right-hand children. Everything down and left are smaller than us, so any ' next ' node must being in the general direction to our parent. Go up the tree; Any time the ancestor was a right-hand child of it parent, keep going up. The IT ' s a left-hand child of it parent, said parent are our ' next ' node. */while (parent = rb_parent (node) && node = = Parent->rb_riGht) node = parent; 
return to parent;  }

Vi. using in Applications

The implementation of the red-black tree algorithm in the Linux kernel is very common, ingenious, and free and open source, so it can be applied to its own applications.

(1), copy source files from the kernel:

$ mkdir redblack 
$ cd redblack/ 
$ CP. /linux-2.6.38.8/lib/rbtree.c. 

(2), modify the source file:

A, c file rbtree.c

Modifying code that contains header files

Delete the following two lines 
of code #include <linux/rbtree.h> 
#include <linux/module.h> 
//Add the following code, that contains the header file in the current directory rbtree.h 

Remove all Export_symbol macros

Export_symbol (Rb_insert_color); 
Export_symbol (rb_erase); 
Export_symbol (Rb_augment_insert); 
Export_symbol (rb_augment_erase_begin); 
Export_symbol (rb_augment_erase_end); 
Export_symbol (Rb_first); 
Export_symbol (rb_last); 
Export_symbol (rb_next); 
Export_symbol (Rb_prev); 

b, header file rbtree.h

Delete the code that contains the header file and add three macro definitions

Delete the following two lines of code 
#include <linux/kernel.h> 
#include <linux/stddef.h>/ 
 
* linux-2.6.38.8/include/ linux/stddef.h/ 
#undef null 
#if defined (__cplusplus) 
#define NULL 0 
#else 
#define NULL (void *) 0) 
#endif/ 
 
* linux-2.6.38.8/include/linux/stddef.h/ 
#define OFFSETOF (TYPE, member) (size_t) & ( TYPE *) 0->member) 
 
/* linux-2.6.38.8/include/linux/kernel.h/ 
#define CONTAINER_OF (PTR, type, member) ( {     \ 
  const typeof ((type *) 0)->member) *__mptr = (ptr); \ 
  

(3), sample code

How to use the Linux kernel red and black tree refer to the linux-2.6.38.8/documentation/rbtree.txt file.

/* test.c/* #include <stdio.h> #include <stdlib.h> #include "rbtree.h" struct MyType {struct RB_NO 
  De My_node; 
int num; 
 
}; 
 
  struct MyType *my_search (struct rb_root *root, int num) {struct Rb_node *node = root->rb_node; 
 
  while (node) {struct MyType *data = container_of (node, struct mytype, my_node); 
  if (num < data->num) node = node->rb_left; 
  else if (num > Data->num) node = node->rb_right; 
  else return data; 
return NULL; int My_insert (struct rb_root *root, struct mytype *data) {struct Rb_node **tmp = & (Root->rb_node), *paren 
 
  t = NULL; /* Figure out where to put new node */while (*tmp) {struct MyType *this = container_of (*tmp, struct mytype, My_nod 
 
  e); 
  parent = *tmp; 
  if (Data->num < this->num) tmp = & ((*tmp)->rb_left); 
  else if (Data->num > This->num) tmp = & ((*tmp)->rb_right); 
  else return-1; 
 }  
  /* ADD new node and rebalance tree. 
  * * Rb_link_node (&data->my_node, parent, TMP); 
   
  Rb_insert_color (&data->my_node, Root); 
return 0; 
  } void My_delete (struct rb_root *root, int num) {struct MyType *data = my_search (root, num); 
  if (!data) {fprintf (stderr, "not found%d.\n", num); 
  Return 
  } rb_erase (&data->my_node, Root); 
Free (data); 
   
  } void Print_rbtree (struct rb_root *tree) {struct rb_node; 
   
  for (node = Rb_first (tree); node node = rb_next (node)) printf ("%d", rb_entry (node, struct MyType, My_node)->num); 
printf ("\ n"); 
  int main (int argc, char *argv[]) {struct Rb_root mytree = rb_root; 
  int i, RET, num; 
 
  struct MyType *tmp; 
  if (ARGC < 2) {fprintf (stderr, "Usage:%s num\n", argv[0]); 
  Exit (-1); 
 
  num = atoi (argv[1]); 
  printf ("Please enter%d integers:\n", num); 
  for (i = 0; i < num i++) {tmp = malloc (sizeof (struct mytype)); if (!tmp)
    Perror ("Allocate dynamic Memory"); 
   
  scanf ("%d", &tmp->num); 
  ret = My_insert (&mytree, TMP); 
    if (Ret < 0) {fprintf (stderr, "The%d already exists.\n", tmp->num); 
  Free (TMP); 
  } printf ("\nthe-test\n"); 
 
  Print_rbtree (&mytree); 
 
  My_delete (&mytree, 21); 
  printf ("\nthe second test\n"); 
 
  Print_rbtree (&mytree); 
return 0;  }

Compile and execute:

$ gcc rbtree.c test.c-o Test 
richard@tanglinux:~/algorithm/redblack$/test please 
enter integers: 
23 
4 
122 the 
already exists 
 
of the same. The 
4 122 the  
 
second Test 
4 12 23 32 45 56 89 122  

Vii. Summary

The above is about the Linux kernel of the red and black tree algorithm to achieve the full content of the article introduced in detail, I hope that everyone's work and learning can help, if there are questions can be exchanged message.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.