红黑树

32 阅读7分钟

红黑树性质

  • 每个结点是红的或者黑的
  • 根结点是黑的
  • 每个叶子结点是黑的
  • 如果一个结点是红的,则它的两个儿子都是黑的
  • 对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点

定义红黑树


typedef int KEY_TYPE;

#define RBTREE_ENTRY(name, type)                              \
  struct name {                                               \
    struct type *right;  /*因为红黑树也是二叉树,所以定义左右子树*/   \  
    struct type *left;                                          \
    struct type *parent;    /*在做红黑树调整时候需要用到*/          \ 
    unsigned char color;     /*定义结点是红色还是黑色*/            \ 
  }
  

// 定义结点结构

typedef struct _rbtree_node {
  KEY_TYPE key;   // 红黑树主要用于查找的,因此定义key和value
  void *value;

  RBTREE_ENTRY(, _rbtree_node) node;

} rbtree_node;

// 定义红黑树

typedef struct _rbtree {
  struct _rbtree_node *root;
  struct _rbtree_node *nil;


} rbtree;

红黑树旋转

当红黑树性质被破坏时候需要进行旋转,分为左旋和右旋,左旋与右旋不需要改变颜色。

image.png

实现左旋

在该结构基础上进行左旋

image.png

void rbtree_left_rotate(rbtree *T, rbtree_node *x) {
  rbtree_node *y = x->node->right;

  // 需要同时改变两个指针的指向
  x->node->right = y->node->left;   // x的右结点为b

  if (y->node->left->node != T->nil) {
    // 不是叶子结点才进行父节点指向的改变
    y->node->left->node->parent = x;  // y的左结点的父节点变为x
  }

  y->node->parent = x->node->parent;

  if (x->node->parent == T->nil) {
    // 如果x为根节点
    T->root = y;
  } else if (x == x->node->parent->node->left) {
    // x是其parent结点的左子树
    x->node->parent->node->left = y;
  } else {
    // x是其parent结点的右子树
    x->node->parent->node->right = y;
  }

  y->node->left = x;
  x->node->parent = y;


}



实现右旋

在该结构上进行右旋

image.png

如果左旋实现好的话,右旋实现会很方便,只要将左旋代码复制,然后将left改为right,right改为left,x改为y,y改为x即可

void rbtree_right_rotate(rbtree *T, rbtree_node *y) {
  rbtree_node *x = y->node->left;

  // 需要同时改变两个指针的指向
  y->node->left = x->node->right;  

  if (x->node->right->node != T->nil) {
    // 不是叶子结点才进行父节点指向的改变
    x->node->right->node->parent = y; 
  }

  x->node->parent = y->node->parent;

  if (x->node->parent == T->nil) {
    T->root = x;
  } else if (y == y->node->parent->node->right) {
    y->node->parent->node->right = x;
  } else {
    y->node->parent->node->left = x;
  }

  x->node->right = y;
  y->node->parent = x;


}



插入数据

红黑树中插入结点会添加到树的最底层

void rbtree_insert_fixup(rbtree *T, rbtree_node *z) {
  // 调整红黑树的函数
  while(z->node->parent->node->color == RED) {
    // z自己是红色,父节点也是红色,祖父结点是黑色,叔父结点颜色不确定

    if (z->node->parent == z->node->parent->node->parent->node->left) {
      // 如果z的父节点是祖父结点的左子树
      rbtree_node *y = z->node->parent->node->parent->node->right;  // 获得叔父结点

      if(y->node->color == RED) {
        // 如果叔父结点颜色为红色
        z->node->parent->node->parent->node->color = RED;  // 将祖父结点变为红色
        y->node->color = BLACK;  // 叔父结点变为黑色
        z->node->parent->node->color = BLACK; // 将父节点变为黑色

        z = z->node->parent->node->parent;  // z始终为红色,进行递归改变颜色
      } else {
        // 如果叔父结点为黑色

        if (z == z->node->parent->node->right) {
          z = z->node->parent;
          rbtree_left_rotate(T, z);  // 先进性左旋,会得到一个中间状态,该状态不满足红黑树的定义,需要再进行一次变换
        }

        if (z == z->node->parent->node->left) {
          // 左边比较重
          z->node->parent->node->color = BLACK;
          z->node->parent->node->parent->node->color = RED;

          // 以祖父结点进行右旋
          rbtree_right_rotate(T, z->node->parent->node->parent->node);
        } 

      }

    } else {

    }

  }

}

void rbtree_insert(rbtree *T, rbtree_node *z) {
  rbtree_node *x = T->root;
  rbtree_node *y = T->nil;

  while(x != T->nil) {
    y = x;  // y始终比x高一级
    if (z->key < x->key) {
      x = x->node->left;
    } else  if (z->key > x->key) {
      x = x->node->right;
    } else {
      // key相等,红黑树定义中没有关于key相等的话如何处理,可以根据自己的业务进行处理
      return;
    }

  }

  // 如果红黑树一个结点也没有
  if (y == T->nil) {
    T->root = z;
  }

  // 将z插入到y的左子树还是右子树
  if (y->key > z->key) {
    // 插入到y的左子树上
    y->node->left = z;
  } else {
    y->node->right = z;
  }

  // 修改下插入的z结点的属性
  z->node->parent = y;
  z->node->left = T->nil;
  z->node->right = T->nil;

  // 红黑树在插入结点之前已经是红黑树了
  z->node->color = RED;  // 上红色,定义为红色第四条性质可能不满足,其他的几个条件满足,然后调整红黑树

  rbtree_insert_fixup(T, z);


}


完整代码


#define RED   0
#define BLACK 1

typedef int KEY_TYPE;

#define RBTREE_ENTRY(name, type)                              \
  struct name {                                               \
    struct type *right;  /*因为红黑树也是二叉树,所以定义左右子树*/   \  
    struct type *left;                                          \
    struct type *parent;    /*在做红黑树调整时候需要用到*/          \ 
    unsigned char color;     /*定义结点是红色还是黑色*/            \ 
  }
  

// 定义结点结构

typedef struct _rbtree_node {
  KEY_TYPE key;   // 红黑树主要用于查找的,因此定义key和value
  void *value;

  RBTREE_ENTRY(, _rbtree_node) *node;

} rbtree_node;

// 定义红黑树

typedef struct _rbtree {
  struct _rbtree_node *root; // 根节点
  struct _rbtree_node *nil;  // 叶子结点


} rbtree;

// 左旋

void rbtree_left_rotate(rbtree *T, rbtree_node *x) {
  rbtree_node *y = x->node->right;

  // 需要同时改变两个指针的指向
  x->node->right = y->node->left;   // x的右结点为b

  if (y->node->left->node != T->nil) {
    // 不是叶子结点才进行父节点指向的改变
    y->node->left->node->parent = x;  // y的左结点的父节点变为x
  }

  y->node->parent = x->node->parent;

  if (x->node->parent == T->nil) {
    // 如果x为根节点
    T->root = y;
  } else if (x == x->node->parent->node->left) {
    // x是其parent结点的左子树
    x->node->parent->node->left = y;
  } else {
    // x是其parent结点的右子树
    x->node->parent->node->right = y;
  }

  y->node->left = x;
  x->node->parent = y;


}


// 右旋

void rbtree_right_rotate(rbtree *T, rbtree_node *y) {
  rbtree_node *x = y->node->left;

  // 需要同时改变两个指针的指向
  y->node->left = x->node->right;  

  if (x->node->right->node != T->nil) {
    // 不是叶子结点才进行父节点指向的改变
    x->node->right->node->parent = y; 
  }

  x->node->parent = y->node->parent;

  if (x->node->parent == T->nil) {
    T->root = x;
  } else if (y == y->node->parent->node->right) {
    y->node->parent->node->right = x;
  } else {
    y->node->parent->node->left = x;
  }

  x->node->right = y;
  y->node->parent = x;


}

// 插入数据

void rbtree_insert_fixup(rbtree *T, rbtree_node *z) {
  // 调整红黑树的函数
  while(z->node->parent->node->color == RED) {
    // z自己是红色,父节点也是红色,祖父结点是黑色,叔父结点颜色不确定

    if (z->node->parent == z->node->parent->node->parent->node->left) {
      // 如果z的父节点是祖父结点的左子树
      rbtree_node *y = z->node->parent->node->parent->node->right;  // 获得叔父结点

      if(y->node->color == RED) {
        // 如果叔父结点颜色为红色
        z->node->parent->node->parent->node->color = RED;  // 将祖父结点变为红色
        y->node->color = BLACK;  // 叔父结点变为黑色
        z->node->parent->node->color = BLACK; // 将父节点变为黑色

        z = z->node->parent->node->parent;  // z始终为红色,进行递归改变颜色
      } else {
        // 如果叔父结点为黑色

        if (z == z->node->parent->node->right) {
          z = z->node->parent;
          rbtree_left_rotate(T, z);  // 先进性左旋,会得到一个中间状态,该状态不满足红黑树的定义,需要再进行一次变换
        }

        if (z == z->node->parent->node->left) {
          // 左边比较重
          z->node->parent->node->color = BLACK;
          z->node->parent->node->parent->node->color = RED;

          // 以祖父结点进行右旋
          rbtree_right_rotate(T, z->node->parent->node->parent->node);
        } 

      }

    } else {

    }

  }

}

void rbtree_insert(rbtree *T, rbtree_node *z) {
  rbtree_node *x = T->root;
  rbtree_node *y = T->nil;

  while(x != T->nil) {
    y = x;  // y始终比x高一级
    if (z->key < x->key) {
      x = x->node->left;
    } else  if (z->key > x->key) {
      x = x->node->right;
    } else {
      // key相等,红黑树定义中没有关于key相等的话如何处理,可以根据自己的业务进行处理
      return;
    }

  }

  // 如果红黑树一个结点也没有
  if (y == T->nil) {
    T->root = z;
  }

  // 将z插入到y的左子树还是右子树
  if (y->key > z->key) {
    // 插入到y的左子树上
    y->node->left = z;
  } else {
    y->node->right = z;
  }

  // 修改下插入的z结点的属性
  z->node->parent = y;
  z->node->left = T->nil;
  z->node->right = T->nil;

  // 红黑树在插入结点之前已经是红黑树了
  z->node->color = RED;  // 上红色,定义为红色第四条性质可能不满足,其他的几个条件满足,然后调整红黑树

  rbtree_insert_fixup(T, z);


}