c語言手搓int紅黑樹(2020.12.25更新至節點添加)


轉自我自己的博客:https://blog.laclic.ink/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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM