c语言手搓int红黑树(2020.12.25更新至节点添加)

转自我自己的博客:https://blog.laclic.top/2020/12/25/RBtree/

思路来源:Wechat article.

int 型 红黑树

 采用了双向结构,子节点可指向父节点
 代码采用了多.c文件形式,需要在一个project下进行编译

函数名 英文释义 中文释义
treeCrt() Tree Create 创建树
treeAdd() Tree Add 向树添加节点
treePrt() Tree Print 打印树/输出树
|||
_treeAdd_recur() Tree Add Recursion 通过递归方式查找插入位点并插入
_treeJug() Tree Judge 比较判断节点值的大小关系
_treePrt_recur() Tree Print Recursion 通过递归方式打印树
_treeChk() Tree Check 检查节点附近的情况
_treeRot() Tree Rotate 选择树的结点
_nodeCrt() Node Create 创建并返回一个带值的节点

 注:开头带下划线的函数表示私有函数(不希望直接被访问,只是为了给非下划线函数使用方便)

头文件:


#ifndef _TREE_H_
#define _TREE_H_
#include <stdio.h>
#include <stdlib.h>

typedef struct _node
{
  int value;
  struct _node *p[2]; // p[0]: left-son, p[1]: right-son
  struct _node *father;
  char BR; // 0: black; 1: red; 
}Node;

typedef struct _rbtree
{
  Node* head;
}RBTree;

RBTree treeCrt();
void treeAdd(RBTree* t,int value);
void treePrt(RBTree t);
void _treeAdd_recur(Node* now,const int value);
void _treePrt_recur(Node* now,int layer);
void _treeChk(Node* now,int son);
int _treeJdg(Node* const now,const int value);
void _treeRot(Node* now,const int drc); // lift the left or right one to now position, drc means direction
Node* _nodeCrt(Node* father,int value);

#endif

红黑树 的 创建 与 添加

函数名 英文释义 中文释义
treeCrt() Tree Create 创建树
treeAdd() Tree Add 向树添加节点
_treeAdd_recur() Tree Add Recursion 通过递归方式查找插入位点并插入
_treeJug() Tree Judge 比较判断节点值的大小关系
_nodeCrt() Node Create 创建并返回一个带值的节点

#include "tree.h"

RBTree treeCrt() {
  RBTree t = {NULL};
  return t;
}

#include "tree.h"

void treeAdd(RBTree*t,int value) { // 将添加函数进行了封装,而非直接用主函数来进行递归
  if(t->head) _treeAdd_recur(t->head,value);
  else t->head = _nodeCrt(NULL,value);
  t->head->BR = 0;
}

void _treeAdd_recur(Node* now,int value) {
  int drc = _treeJdg(now,value); // drc: direction, left(0) or right(1) // _treeJdg()函数用于判断大小以确定
  if(now->p[drc]) _treeAdd_recur(now->p[drc],value);
  else {
    now->p[drc] = _nodeCrt(now,value);
    _treeChk(now,drc); // 用于检查红黑关系的函数
  }
}
#include "tree.h"
int _treeJdg(Node* const now,const int value) {
    return now->value < value;
  }
#include "tree.h"

Node* _nodeCrt(Node* father,int value) {
  Node* node = (Node*) malloc(sizeof(Node));
  node->father = father;
  node->p[0] = NULL;
  node->p[1] = NULL;
  node->value = value;
  node->BR = 1;
}

红黑树 的 打印/输出/展示

 由于输出的特性,我们无法竖着输出我们所熟悉的二叉树,只能通过递归的方式来横向输出我们的二叉树

函数名 英文释义 中文释义
treePrt() Tree Print 打印树/输出树
_treePrt_recur() Tree Print Recursion 通过递归方式打印树

#include "tree.h"

void treePrt(RBTree t) { // 同样是进行了封装
  if(t.head) _treePrt_recur(t.head,0); // 判断空树,如果t上有结点(不是空树)就进入递归
  else printf("This is an empty tree.\n"); // 否则,输出空树
  printf("------------------------------------\n"); // 分隔符
}

void _treePrt_recur(Node* now,int layer) { // layer 代指当前所处的层数/递归的深度
  if(now->p[1]) _treePrt_recur(now->p[1],layer+1);
  for(int i=0;i<layer;++i) printf("\t"); // 制表符,让格式更好看
  printf("%d(BR-%d)\n",now->value,now->BR);
  if(now->p[0]) _treePrt_recur(now->p[0],layer+1);
}

红黑树 的 检查与旋转

函数名 英文释义 中文释义
_treeChk() Tree Check 检查节点附近的情况
_treeRot() Tree Rotate 选择树的结点

 检查新插入节点、其父节点,以及其祖父节点(父节点的父节点)


#include "tree.h"

void _treeChk(Node* f,int son) { // son of father(f) is the added node
  int status = 0b00; // if (son > f) ==> 0b1??, son > gf ==> 0b?1?
  Node* gf = f->father;
  Node* s; // s means son, Node*
  if(gf&&f->BR) {
    if(gf->p[0]&&gf->p[1]&&gf->p[0]->BR&&gf->p[1]->BR) { 
      // left-son and right-son exists, left and right sons are both red
      gf->BR = 1;
      gf->p[0]->BR = 0;
      gf->p[1]->BR = 0;
      if(gf->father) {
        _treeChk(gf->father,gf->value > gf->father->value); 
      }
    }else {
      status = son;
      s = f->p[son]; // s means son of f, Node*
      status = (status << 1) + (f->p[son]->value > gf->value);
      switch(status) {
        case 0b00 : ;
        case 0b11 : 
          f->BR = 1;
          gf->BR = 0;
          _treeRot(gf,!(1&status));
          break;
        case 0b10 : ;
        case 0b01 : 
          f->BR = 1;
          gf->BR = 0;
          _treeRot(f,!son);
          _treeRot(gf,!(1&status));
          break;
        default : ;
      }
    }
  }
  return;
}

 以下函数中的drc,0代表左旋,1代表右旋


#include "tree.h"

void _treeRot(Node* now,const int drc) { // left-rotate: 0
  now->value ^= now->p[!drc]->value ^= now->value ^= now->p[!drc]->value; // swap value
  Node* temp = now->p[drc];
  now->p[drc] = now->p[!drc];
  now->p[!drc] = now->p[drc]->p[!drc];
  now->p[drc]->p[!drc] = now->p[drc]->p[drc];
  now->p[drc]->p[drc] = temp;
  if(temp) temp->father = now->p[drc];
  if(now->p[!drc]) now->p[!drc]->father = now;
}
posted @ 2021-03-25 10:18  LacLic  阅读(188)  评论(13编辑  收藏  举报