平衡树基础

一,二叉排序树

1.结构定义

2.结构操作

(1)节点 插入
  • 从根节点开始,逐层比较
  • 要插入的节点比当前节点大,指针往右子树移
  • 要插入的节点比当前节点小,指针往左子树移
  • 直到遍历到空节点,根据上述规则,插入到空节点
(2)节点删除
1、删除叶 节点 
  • 直接删除
2、删除出度为1的节点 
  • 提升唯一的子树
3、删除出度为2的节点
  • 找到要删除节点的前驱或者后继,与其中之一替换后,转换为度为1的节点问题
前驱:从要删除的节点的左子树开始,向右遍历到的最大节点为要删除的节点的前驱
后继:从要删除的节点的右子树开始,向左遍历到的最小节点为要删除的节点的后继
代码实现:
#include <iostream>
#include <cstdio>
#include <ctime>
#include <cstdlib>
using namespace std;
#define KEY(n) (n ? n->key : -1)
typedef struct Node {
        int key;
        struct Node* lchild, * rchild;
}Node;
Node* getNewNode( int key) {
       Node* p = (Node*)malloc( sizeof (Node));
       p->key = key;
       p->lchild = p->rchild = NULL;
        return p;
}
//插入,返回当前子树根节点
Node* insert( Node * root , int key ) {
        if ( root == NULL ) return getNewNode( key );
        if ( root ->key == key ) return root ;
        if ( key > root ->key) root ->rchild = insert( root ->rchild, key );
        else root ->lchild = insert( root ->lchild, key );
        return root ;
}
Node * predecessor( Node * root ) {
        Node * temp = root ->lchild;
        while (temp->rchild)temp = temp->rchild;
        return temp;
}
//删除,返回当前子树根节点
Node * erase( Node * root , int key ) {
        if ( root == NULL ) return root ;
        if ( key < root ->key) root ->lchild = erase( root ->lchild, key );
        else if ( key > root ->key) root ->rchild = erase( root ->rchild, key );
        else {
               //要删除节点出度为0的节点
               if ( root ->rchild == NULL && root ->lchild == NULL ) {
                      free( root );
                       //返回给父节点指针
                       return NULL ;
              }
               //要删除节点出度为1的节点
               else if ( root ->lchild == NULL || root ->rchild == NULL ) {
                       Node * temp = root ->lchild ? root ->lchild : root ->rchild;
                      free( root );
                       return temp;
              }
               //要删除节点出度为2的节点
               else {
                       Node * temp = predecessor( root );
                       root ->key = temp->key;
                       root ->lchild = erase( root ->lchild, temp->key);
              }
       }
        return root ;
}
void clear( Node * root ) {
        if ( root == NULL ) return ;
       clear( root ->lchild);
       clear( root ->rchild);
       free( root );
        return ;
}
//前序遍历
void output( Node * root ) {
        if ( root == NULL ) return ;
       printf( "(%d ; %d, %d)\n" ,
               KEY ( root ),
               KEY ( root ->lchild),
               KEY ( root ->rchild)
       );
       output( root ->lchild);
       output( root ->rchild);
        return ;
}
//中序遍历
void in_order( Node * root ) {
        if ( root == NULL ) return ;
       in_order( root ->lchild);
       printf( "%d " , root ->key);
       in_order( root ->rchild);
        return ;
}
int main() {
       srand(time(0));
#define MAX_OP 10
        Node * root = NULL ;
        for ( int i = 0; i < MAX_OP ; i++) {
               int key = rand() % 100;
              printf( "insert key %d to BST\n" , key);
              root = insert(root, key);
       }
       output(root);
       printf( "in order : " );
       in_order(root);
       printf( "\n" );
        int x;
        while (~scanf_s( "%d" , &x)) {
              printf( "erase %d from BST\n" , x);
              root = erase(root, x);
              in_order(root); printf( "\n" );
       }
        return 0;
}

二,AVL树

1.k1为从下往上看的第一个失衡的位置(k1左右子树的高度差大于1)
2.LL型k1的左子树要更高,k1的左子树的左子树要更高(和各自的右子树相比)
RL型 -->先小右旋,在大左旋
代码演示:
#include <iostream>
#include <cstdio>
#include <ctime>
#include <cmath>
#include <cstdlib>
using namespace std;
typedef struct Node {
        int key, h;
        struct Node * rchild, * lchild;
} Node ;
//创建虚拟空节点
Node __NIL;
#define NIL (&__NIL)
#define K (n) (n->key)
#define H (n) (n->h)
#define L (n) (n->lchild)
#define R (n) (n->rchild)
//初始化虚拟空节点
__attribute__((constructor));
void init__NIL() {
        K ( NIL ) = -1;
        H ( NIL ) = 0;
        L ( NIL ) = R ( NIL ) = NIL ;
        return ;
}
Node * getNewNode( int key ) {
        Node * p = ( Node *)malloc( sizeof ( Node ));
       p->key = key ;
       p->h = 1;
       p->lchild = p->rchild = NIL ;
        return p;
}
//更新根节点的高度
void update_height( Node * root ) {
        H ( root ) = ( H ( L ( root )) > H ( R ( root )) ? H ( L ( root )) : H ( R ( root ))) + 1;
        return ;
}
//左旋
Node * left_rotate( Node * root ) {
       printf( "left rotate : %d\n" , root ->key);
        Node * new_node = root ->rchild;
        root ->rchild = new_node->lchild;
       new_node->lchild = root ;
       update_height( root );
       update_height(new_node);
        return new_node;
}
//右旋
Node * right_rotate( Node * root ) {
       printf( "right rotate : %d\n" , root ->key);
        Node * new_node = root ->lchild;
        root ->lchild = new_node->rchild;
       new_node->rchild = root ;
       update_height( root );
       update_height(new_node);
        return new_node;
}
//维护类型--失衡类型
const char * type_str[5] = {
        "" ,
        "maintain type : LL"
        "maintain type : LR"
        "maintain type : RR"
        "maintain type : RL"
};
//维护平衡状态
Node * maintain( Node * root ) {
        //不用维护
        if (abs( H ( L ( root )) - H ( R ( root ))) <= 1) return root ;
        //记录失衡类型
        int type = 0;
        if ( H ( L ( root )) > H ( R ( root ))) {
               if ( H ( R ( L ( root ))) > H ( L ( L ( root )))) {
                       // LR --> 小左旋
                       root ->lchild = left_rotate( root ->lchild);
                      type += 1;
              }
               // LL/LR --> 大右旋
               root = right_rotate( root );
              type += 1;
       }
        else {
               if ( H ( L ( R ( root ))) > H ( R ( R ( root )))) {
                       //RL --> 小右旋
                       root ->rchild = right_rotate( root ->rchild);
                      type += 1;
              }
               // RR/RL --> 大左旋
               root = left_rotate( root );
              type += 1;
       }
       printf( "%s\n" , type_str[type]);
        return root ;
}
Node * insert( Node * root , int key ) {
        if ( root == NIL ) return getNewNode( key );
        if ( root ->key == key ) return root ;
        if ( key < root ->key) root ->lchild = insert( root ->lchild, key );
        else root ->rchild = insert( root ->rchild, key );
        //重新计算当前节点高度
       update_height( root );
        //维护平衡
        return maintain( root );
}
Node * predecessor( Node * root ) {
        Node * temp = root ->lchild;
        while (temp->rchild != NIL ) temp = temp->rchild;
        return temp;
}
Node * erase( Node * root , int key ) {
        if ( root == NIL ) return root ;
        if ( key < root ->key) root ->lchild = erase( root ->lchild, key );
        else if ( key > root ->key) root ->rchild = erase( root ->rchild, key );
        else {
               //删除度为0,1的节点
               if ( root ->lchild == NIL || root ->rchild == NIL ) {
                       Node * temp = root ->lchild != NIL ? root ->lchild : root ->rchild;
                      free( root );
                       return temp;
              }
               //删除度为2的节点
               else {
                       Node * temp = predecessor( root );
                       root ->key = temp->key;
                       root ->lchild = erase( root ->lchild, temp->key);
              }
       }
        //重新计算当前节点高度
       update_height( root );
        //维护平衡
        return maintain( root );
}
Node * find( Node * root , int key ) {
        if ( root == NIL ) return NIL ;
        if ( root ->key == key ) return root ;
        if ( key < root ->key) return find( root ->lchild, key );
        return find( root ->rchild, key );
}
void clear( Node * root ) {
        if ( root == NULL ) return ;
       clear( root ->lchild);
       clear( root ->rchild);
       free( root );
        return ;
}
//前序遍历
void output( Node * root ) {
        if ( root == NIL ) return ;
       printf( "(%d[%d] | %d, %d)\n" ,
               K ( root ), H ( root ),
               K ( L ( root )), K ( R ( root ))
       );
       output( root ->lchild);
       output( root ->rchild);
        return ;
}
int main() {
       srand(time(0));
        Node * root = NIL ;
        int x;
        // insert
        while (~scanf_s( "%d" , &x)) {
               if (x == -1) break ;
              printf( "insert %d to avl tree\n" , x);
              root = insert(root, x);
              output(root);
       }
        // erase
        while (~scanf_s( "%d" , &x)) {
               if (x == -1) break ;
              printf( "erase %d from avl tree\n" , x);
              root = erase(root, x);
              output(root);
       }
        // find
        while (~scanf_s( "%d" , &x)) {
               if (x == -1) break ;
              printf( "find %d in avl : %d\n" , x, find(root, x) != NIL );
       }
        return 0;
}

三,红黑树

插入操作

原则:
  • 调整前后,每条路径黑色节点数不变。
  • 对于颜色不确定的节点,其父节点一定是黑色。
  • 插入到红黑树的节点一定为红色。
情况1:
调整方法:
将祖父节点调整成红色,叔父节点和父节点调整成黑色
情况2:
左边红色节点的左子树是红色,导致失衡--LL型
调整方式: 大右旋-->红色上浮/下沉(大右旋后的根节点及其左右子树改成了红黑黑/黑红红)
情况3:
左边红色节点的右子树是红色,导致失衡--LR型
调整方式: 小左旋 --> 大右旋-->红色上浮/下沉(大右旋后的根节点及其左右子树改成了红黑黑/黑红红)
情况4:
右边红色节点的右子树是红色,导致失衡--RR型
调整方式: 大左旋-->红色上浮/下沉(大左旋后的根节点及其左右子树改成了红黑黑/黑红红)
情况5:
右边红色节点的左子树是红色,导致失衡--RL型
调整方式: 小右旋 --> 大左旋-->红色上浮/下沉(大右旋后的根节点及其左右子树改成了红黑黑/黑红红)

红黑树的删除操作

1.删除度为零的红色节点:直接删除
2.删除度为1的红色节点:不存在度为1的红色节点,违背了红黑树的第五条性质(不同路径的黑色节点数相同);
3.删除度为1的黑色节点:其唯一子树不能存在黑色节点,修改方法:红提升,并变黑;
以上三种删除情况,不会造成红黑树失衡
4.删除度为0的黑色节点:将被删除的黑色节点的NIL节点设置成双重黑节点;
那么双重黑节点违反了红黑树的性质,引发红黑树的失衡,则 删除调整的操作主要是解决删除度为0的黑色节点而产生的双重黑节点
ps:删除度为2的节点可以转换成删除度为1的节点
删除调整情况:(x是双重黑节点)
1.双重黑节点的兄弟节点是黑色,并且双重黑色的兄弟节点的子节点都为黑色
  • 调整方法: 给父节点加上一重黑,其左右子树减去一重黑。
43:黑/红->双重黑/黑        9:黑->红        95:双重黑->黑
2.双重黑的兄弟节点为黑色,并在右侧,其右子树(记为a)为红色(RR型失衡)
  • RR类型的判断优先级高于RL类型
  • 调整方法:先抓着双重黑节点的父节点大左旋,再将双重黑节点的 兄弟节点的颜色变成原父节点的颜色,原父节点和a(旋转后的根节点的左右子节点)的颜色变成黑色,双重黑节点变成黑色。
3.双重黑的兄弟节点为黑色,并在左侧,其左子树(记为a)为红色(LL型失衡)
  • LL类型的判断优先级高于LR类型
  • 调整方法:先抓着双重黑节点的父节点大右旋,再将双重黑节点的 兄弟节点的颜色变成原父节点的颜色,原父节点和a(旋转后的根节点的左右子节点)的颜色变成黑色,双重黑节点变成黑色。
4.双重黑的兄弟节点为黑色,并在右侧,其左子树(记为b)为红色,且右子树为黑色(RL型失衡)
  • 调整方法:先抓着双重黑节点的兄弟节点小右旋,转换成RR型失衡
5.双重黑的兄弟节点为黑色,并在左侧,其右子树(记为b)为红色,且左子树为黑色(LR型失衡)
  • 调整方法:先抓着双重黑节点的兄弟节点小左旋,转换成LL型失衡
6.双重黑节点的兄弟节点为红色,且位于右侧
  • 调整方法:抓着双重黑节点的父节点大左旋,原根节点修改成红色,新根节点修改成黑色,再次构成情况1/2/3/4/5, 递归到左子树去处理;
蓝框表示节点颜色确定;
7.双重黑节点的兄弟节点为红色,且位于左侧
  • 调整方法:抓着双重黑节点的父节点大右旋,原根节点修改成红色,新根节点修改成黑色,再次构成情况1/2/3/4/5, 递归到右子树去处理;
代码演示:
#include <string>
#include <vector>
#include <iostream>
#include <cinttypes>
#include <iostream>
#include <ctime>
#include <cstdio>
using namespace std;
#define RED     0
#define BLACK   1
#define DBLACK 2
#define NIL (&__NIL)
#define K (n) (n->key)
#define L (n) (n->lchild)
#define R (n) (n->rchild)
#define C (n) (n->color)
typedef struct Node {
        int key, color; // 0 red, 1 black, 2 double black;
        struct Node *rchild, *lchild;
} Node ;
Node __NIL;
void init_NIL() {
        NIL ->key = -1;
        NIL ->rchild = NIL ->lchild = NIL ;
        NIL ->color = BLACK ;
        return ;
}
//为保证相同路径的黑色节点数目相同,新生成的节点为红色
Node * getNewNode( int key ) {
        Node * p = ( Node *)malloc( sizeof ( Node ));
       p->key = key ;
       p->color = RED ;
       p->rchild = p->lchild = NIL ;
        return p;
}
//判断左右子树是否有红色
bool has_red_node( Node * root ) {
        return root ->lchild->color == RED || root ->rchild->color == RED ;
}
//左旋
Node * left_rotate( Node * root ) {
        Node * new_root = root ->rchild;
        root ->rchild = new_root->lchild;
       new_root->lchild = root ;
        return new_root;
}
//右旋
Node * right_rotate( Node * root ) {
        Node * new_root = root ->lchild;
        root ->lchild = new_root->rchild;
       new_root->rchild = root ;
        return new_root;
}
//插入调整
Node * insert_maintain( Node * root ) {
        int flag = 0;
        //判断祖父节点是否为LL/R型(情况2/3)
        if ( C ( L ( root )) == RED && has_red_node( L ( root ))) flag = 1;
        //判断祖父节点是否为RR/L型(情况4/5)
        if ( C ( R ( root )) == RED && has_red_node( R ( root ))) flag = 2;
        //没有出现红色节点的子节点也是红色的情况
        if (flag == 0) return root ;
        //
        if ( C ( L ( root )) == RED && C ( R ( root )) == RED ) goto red_up_maintain;
        if (flag == 1) {
               //LR型判断
               if ( C ( R ( L ( root ))) == RED ) {
                       //小左旋
                       L ( root ) = left_rotate( L ( root ));
              }
               //大右旋
               root = right_rotate( root );
       }
        else {
               //RL型判断
               if ( C ( L ( R ( root ))) == RED ) {
                       //小右旋
                       R ( root ) = right_rotate( R ( root ));
              }
               //大左旋
               root = left_rotate( root );
       }
red_up_maintain:
        C ( root ) = RED ;
        C ( L ( root )) = C ( R ( root )) = BLACK ;
        return root ;
}
//插入
Node * __insert( Node * root , int key ) {
        if ( root == NIL ) return getNewNode( key );
        if ( root ->key == key ) return root ;
        if ( key < root ->key) root ->lchild = __insert( root ->lchild, key );
        else root ->rchild = __insert( root ->rchild, key );
        //插入调整
        return insert_maintain( root );
}
Node * insert( Node * root , int key ) {
        //封装插入功能;
        root = __insert( root , key );
        //保证根节点是黑色
        root ->color = BLACK ;
        return root ;
}
//寻找根节点的前驱
Node * predecessor( Node * root ) {
        Node * temp = root ->lchild;
        while (temp->rchild != NIL )temp = temp->rchild;
        return temp;
}
Node * erase_maintain( Node * root ) {
        if ( C ( L ( root )) != DBLACK && C ( R ( root )) != DBLACK ) return root ;
    //双重黑节点的兄弟节点是红色
        if (has_red_node( root )) {
               //原根节点变成红色
               root ->color = RED ;
               //情况7
               if ( root ->lchild->color == RED ) {
                       root = right_rotate( root );
                       //递归到右子树进行删除调整
                       root ->rchild = erase_maintain( root ->rchild);
              }
               //情况6
               else {
                       root = left_rotate( root );
                       //递归到左子树进行删除调整
                       root ->lchild = erase_maintain( root ->lchild);
              }
               //原红色兄弟节点变成黑色
               root ->color = BLACK ;
               return root ;
       }
        if (( root ->lchild->color == DBLACK && !has_red_node( root ->rchild))
              || ( root ->rchild->color == DBLACK && !has_red_node( root ->lchild))) {
               root ->color += 1;
               root ->lchild->color -= 1;
               root ->rchild->color -= 1;
               return root ;
       }
        if ( root ->rchild->color == DBLACK ) {
               //双重黑节点变成黑色
               root ->rchild->color = BLACK ;
               //LR型失衡
               if ( root ->lchild->lchild->color != RED ) {
                       root ->lchild = left_rotate( root ->lchild);
              }
               //LL型失衡
               root ->lchild->color = root ->color;
               root = right_rotate( root );
       }
        else {
               //双重黑节点变成黑色
               root ->lchild->color = BLACK ;
               //RL型失衡
               if ( root ->rchild->rchild->color != RED ) {
                       root ->rchild = right_rotate( root ->rchild);
              }
               //LL型失衡
               root ->rchild->color = root ->color;
               root = left_rotate( root );
       }
        //旋转后的根节点的左右子节点的颜色变成黑色
        root ->lchild->color = root ->rchild->color = BLACK ;
        return root ;
}
//删除操作
Node * __erase( Node * root , int key ) {
        if ( root == NIL ) return root ;
        if ( key < root ->key) {
               root ->lchild = __erase( root ->lchild, key );
       }
        else if ( key > root ->key) {
               root ->rchild = __erase( root ->rchild, key );
       }
        else {
               //度为0/1的删除情况
               if ( root ->lchild == NIL || root ->rchild == NIL ) {
                       Node * temp = root ->lchild == NIL ? root ->rchild : root ->lchild;
                      temp->color += root ->color;
                      free( root );
                       return temp;
              }
               //度为2的删除情况--转换为度为1/0的删除情况
               Node * temp = predecessor( root );
               root ->key = temp->key;
               root ->lchild = __erase( root ->lchild, temp->key);
       }
        //删除调整
        return erase_maintain( root );
}
//封装删除操作
Node * erase( Node * root , int key ) {
        root = __erase( root , key );
        root ->color = BLACK ;
        return root ;
}
void clear( Node * root ) {
        if ( root == NIL ) return ;
       clear( root ->lchild);
       clear( root ->rchild);
       free( root );
        return ;
}
void output( Node * root ) {
        if ( root == NIL ) return ;
       printf( "(%d| %d; %d, %d)\n" ,
               C ( root ), K ( root ),
               K ( L ( root )), K ( R ( root ))
       );
       output( root ->lchild);
       output( root ->rchild);
        return ;
}
int main() {
       init_NIL();
       srand(time(0));
#define MAX_N 10
        Node * root = NIL ;
        for ( int i = 0; i < MAX_N ; i++) {
               int x = rand() % 100;
              printf( "\ninsert %d to red black tree : \n" , x);
              root = insert(root, x);
              output(root);
       }
        int x;
        while (~scanf_s( "%d" , &x)) {
              printf( "\nerase %d from red black tree\n" , x);
              root = erase(root, x);
              output(root);
       }
        return 0;
}

四,B-树

⼀棵 m 阶 B 树,需要满 下列特性: 
1. 树中每个节点,最多含有 m 棵 树 
2. 若 根节点不是叶 节点,则 少有 2 棵 树 
3. 除根结点之外的所有非终端结点 少有⌈m/2⌉棵 树 (⌈m/2⌉表示m/2向上取整)
4. 如果⼀个结点有n-1个关键字,则该结点有n个分支,且这n-1个关键字按照递增顺序排列 
5. 每个结点的结构为:( n,A0,K1,A1,K2,A2,… ,Kn,An ) 
  • n:节点数量
  • A0 ~ An:分支
  • K1~Kn:节点
  • 节点分支的关系: 例如:A0< K1, K1 < A1 < K2,  K2 < A2 < K3 ..... An > Kn
6. 非根结点中关键字的个数 n,满 :⌈m/2⌉-1 ≤ n ≤ m-1 -->平衡条件关键
7. 所有叶 节点处在同⼀层
m 阶 B 树的性质解读: 
    1. B 树中只有根节点没办法满⾜拥有⾄少 ⌈m/2⌉ 棵⼦树的条件,其他节点均能满⾜
    2. B 树是⼀种 度平衡的树形结构,比 AVL 树结构上更优美
插入操作:
证明:节点分裂的合理性
非根结点中关键字的个数 n,满 :⌈m/2⌉-1 ≤ n ≤ m-1 
当m = 2n + 1
⌈m/2⌉-1 = n;
分裂后:
左子树节点数:(m - 1) / 2 = n
右子树节点数:(m - 1) / 2 = n
当m = 2n
⌈m/2⌉-1 = n - 1;
分裂后:
左子树节点数:(m - 1 - 1) / 2 = n - 1
右子树节点数:(m - 1 + 1) / 2 = n
左右节点数均符合要求
删除操作:
m 阶 B 树的元素删除: 
    1. 终端节点直接删除 
    2. 非终端节点,与(前驱/后继)交换,再删除
代码演示:
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define MAX_M 5
#define MAX_OP 15
typedef struct Node {
        //节点数量
        int n;
        //节点值
        int key[ MAX_M + 1];
        //分支
        struct Node * next[ MAX_M + 1];
} Node ;
Node * getNewNode() {
        Node * p = ( Node *)malloc( sizeof ( Node ));
       p->n = 0;
        //分支数组初始化为NULL
       memset(p->next, 0, sizeof ( Node *) * ( MAX_M + 1));
        return p;
}
//插入操作
//插入调整
Node * insert_maintain( Node * root , Node * child , int pos ) {
        //关键值数没有超过MAX_M
        if ( child ->n < MAX_M ) return root ;
        //要提取的关键值位置
        int spos = MAX_M / 2;
        //分裂成的两个小节点
        Node * node1 = getNewNode();
        Node * node2 = getNewNode();
       node1->n = spos;
       node2->n = MAX_M - 1 - spos;
        //node1的赋值
        for ( int i = 0; i < spos; i++) {
              node1->key[i] = child ->key[i];
              node1->next[i] = child ->next[i];
       }
       node1->next[spos] = child ->next[spos];
        //node2的赋值
        for ( int i = 0; i < node2->n; i++) {
              node2->key[i] = child ->key[i + spos + 1];
              node2->next[i] = child ->next[i + spos + 1];
       }
       node2->next[node2->n] = child ->next[ child ->n];
        //i = root->n 简化了代码
        for ( int i = root ->n; i >= pos ; i--) {
               root ->key[i + 1] = root ->key[i];
               root ->next[i + 1] = root ->next[i];
       }
        root ->key[ pos ] = child ->key[spos];
        root ->next[ pos ] = node1;
        root ->next[ pos + 1] = node2;
        root ->n += 1;
       free( child );
        return root ;
}
Node * insert_key( Node * root , int key ) {
        //根节点为空
        if ( root == NULL ) {
               root = getNewNode();
               root ->key[( root ->n)++] = key ;
               return root ;
       }
        //插入终端节点
        int pos = 0;
        //查找要插入的位置
        while (pos < root ->n && root ->key[pos] < key ) pos += 1;
        if (pos < root ->n && root ->key[pos] == key ) return root ;
        for ( int i = root ->n - 1; i >= pos; i--) {
               root ->key[i + 1] = root ->key[i];
       }
        root ->key[pos] = key ;
        root ->n += 1;
        return root ;
}
Node * __insert( Node * root , int key ) {
        // 根节点为空   || 当前节点为终端节点
        if ( root == NULL || root ->next[0] == NULL ) {
               return insert_key( root , key );
       }
        int pos = 0;
        while (pos < root ->n && root ->key[pos] < key ) pos += 1;
        //判断key是否已经存在
        if (pos < root ->n && root ->key[pos] == key ) return root ;
        //向next[pos]分支遍历
       __insert( root ->next[pos], key );
        return insert_maintain( root , root ->next[pos], pos);
}
Node * insert( Node * root , int key ) {
        root = __insert( root , key );
        //因为插入调整从父节点往下看
        //所以当根节点满了,要单独调整
        if ( root ->n == MAX_M ) {
               //生成空的新根节点
               Node * p = getNewNode();
              p->next[0] = root ;
               root = insert_maintain(p, root , 0);
       }
        return root ;
}
void clear( Node * root ) {
        if ( root == NULL ) return ;
        for ( int i = 0; i <= root ->n; i++) {
              clear( root ->next[i]);
       }
       free( root );
        return ;
}
void print_node( Node * root ) {
       printf( "%d : " , root ->n);
        for ( int i = 0; i < root ->n; i++) {
              printf( "%4d" , root ->key[i]);
       }
       printf( " | " );
        if ( root ->next[0] == NULL ) goto output_end;
        for ( int i = 0; i <= root ->n; i++) {
              printf( "%4d" , root ->next[i]->key[0]);
       }
output_end:
       printf( "\n" );
        return ;
}
void output( Node * root ) {
        if ( root == NULL ) return ;
       print_node( root );
        for ( int i = 0; i <= root ->n; i++) {
              output( root ->next[i]);
       }
        return ;
}
int main() {
       srand(time(0));
        Node * root = NULL ;
        for ( int i = 0; i < MAX_OP ; i++) {
               int val = rand() % 100;
              root = insert(root, val);
              printf( "\ninsert %d to BTree : \n" , val);
              output(root);
       }
        return 0;
}
左旋/右旋:
左子树富裕--右旋,右子树富裕--左旋,
合并:

代码演示:
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define MAX_M 3
#define MAX_OP 12
#define LCHILD (root, pos) (root->next[pos])
#define RCHILD (root, pos) (root->next[pos + 1])
#define LAST_KEY (root) (root->key[root->n - 1])
#define LAST_CHILD (root) (root->next[root->n])
typedef struct Node {
        //关键字数量
        int n;
        //关键字值
        int key[ MAX_M + 1];
        //分支
        struct Node * next[ MAX_M + 1];
} Node ;
Node * getNewNode() {
        Node * p = ( Node *)malloc( sizeof ( Node ));
       p->n = 0;
        //分支数组初始化为NULL
       memset(p->next, 0, sizeof ( Node *) * ( MAX_M + 1));
        return p;
}
//插入操作
//插入调整
Node * insert_maintain( Node * root , Node * child , int pos ) {
        //关键值数没有超过MAX_M
        if ( child ->n < MAX_M ) return root ;
        //要提取的关键值位置
        int spos = MAX_M / 2;
        //分裂成的两个小节点
        Node * node1 = getNewNode();
        Node * node2 = getNewNode();
       node1->n = spos;
       node2->n = MAX_M - 1 - spos;
        //node1的赋值
        for ( int i = 0; i < spos; i++) {
              node1->key[i] = child ->key[i];
              node1->next[i] = child ->next[i];
       }
       node1->next[spos] = child ->next[spos];
        //node2的赋值
        for ( int i = 0; i < node2->n; i++) {
              node2->key[i] = child ->key[i + spos + 1];
              node2->next[i] = child ->next[i + spos + 1];
       }
       node2->next[node2->n] = child ->next[ child ->n];
        //i = root->n 简化了代码
        for ( int i = root ->n; i >= pos ; i--) {
               root ->key[i + 1] = root ->key[i];
               root ->next[i + 1] = root ->next[i];
       }
        root ->key[ pos ] = child ->key[spos];
        root ->next[ pos ] = node1;
        root ->next[ pos + 1] = node2;
        root ->n += 1;
       free( child );
        return root ;
}
Node * insert_key( Node * root , int key ) {
        //根节点为空
        if ( root == NULL ) {
               root = getNewNode();
               root ->key[( root ->n)++] = key ;
               return root ;
       }
        //插入终端节点
        int pos = 0;
        //查找要插入的位置
        while (pos < root ->n && root ->key[pos] < key ) pos += 1;
        if (pos < root ->n && root ->key[pos] == key ) return root ;
        for ( int i = root ->n - 1; i >= pos; i--) {
               root ->key[i + 1] = root ->key[i];
       }
        root ->key[pos] = key ;
        root ->n += 1;
        return root ;
}
Node * __insert( Node * root , int key ) {
        // 根节点为空   || 当前节点为终端节点
        if ( root == NULL || root ->next[0] == NULL ) {
               return insert_key( root , key );
       }
        int pos = 0;
        while (pos < root ->n && root ->key[pos] < key ) pos += 1;
        //判断key是否已经存在
        if (pos < root ->n && root ->key[pos] == key ) return root ;
        //向next[pos]分支遍历
       __insert( root ->next[pos], key );
        return insert_maintain( root , root ->next[pos], pos);
}
Node * insert( Node * root , int key ) {
        root = __insert( root , key );
        //因为插入调整从父节点往下看
        //所以当根节点满了,要单独调整
        if ( root ->n == MAX_M ) {
               //生成空的新根节点
               Node * p = getNewNode();
              p->next[0] = root ;
               root = insert_maintain(p, root , 0);
       }
        return root ;
}
//删除操作
void erase_pos( Node * root , int pos ) {
        for ( int i = pos + 1; i < root ->n; i++) {
               root ->key[i - 1] = root ->key[i];
       }
        root ->n -= 1;
        return ;
}
//删除调整
//右旋
void right_rotate( Node * root , int pos ) {
        for ( int i = RCHILD ( root , pos )->n + 1; i > 0; i--) {
               RCHILD ( root , pos )->key[i] = RCHILD ( root , pos )->key[i - 1];
               RCHILD ( root , pos )->next[i] = RCHILD ( root , pos )->next[i - 1];
       }
        RCHILD ( root , pos )->key[0] = root ->key[ pos ];
        root ->key[ pos ] = LAST_KEY ( LCHILD ( root , pos ));
        RCHILD ( root , pos )->next[0] = LAST_CHILD ( LCHILD ( root , pos ));
        LAST_CHILD ( LCHILD ( root , pos )) = NULL ;
        RCHILD ( root , pos )->n += 1;
        LCHILD ( root , pos )->n -= 1;
        return ;
}
//左旋
void left_rotate( Node * root , int pos ) {
        LCHILD ( root , pos )->key[ LCHILD ( root , pos )->n] = root ->key[ pos ];
        LCHILD ( root , pos )->n += 1;
        root ->key[ pos ] = RCHILD ( root , pos )->key[0];
        LAST_CHILD ( LCHILD ( root , pos )) = RCHILD ( root , pos )->next[0];
        for ( int i = 0; i < RCHILD ( root , pos )->n; i++) {
               RCHILD ( root , pos )->key[i] = RCHILD ( root , pos )->key[i + 1];
               RCHILD ( root , pos )->next[i] = RCHILD ( root , pos )->next[i + 1];
       }
        LAST_CHILD ( RCHILD ( root , pos )) = NULL ;
        RCHILD ( root , pos )->n -= 1;
        return ;
}
void merge_node( Node * root , int pos ) {
        Node * node = getNewNode();
        //拷贝pos左分支
        for ( int i = 0; i <= LCHILD ( root , pos )->n; i++) {
              node->key[i] = LCHILD ( root , pos )->key[i];
              node->next[i] = LCHILD ( root , pos )->next[i];
       }
        //拷贝root->key[pos]
       node->n = LCHILD ( root , pos )->n + 1;
       node->key[node->n - 1] = root ->key[ pos ];
        //拷贝pos右分支
        for ( int i = 0; i <= RCHILD ( root , pos )->n; i++) {
              node->key[i + node->n] = RCHILD ( root , pos )->key[i];
              node->next[i + node->n] = RCHILD ( root , pos )->next[i];
       }
       node->n += RCHILD ( root , pos )->n;
       free( LCHILD ( root , pos ));
       free( RCHILD ( root , pos ));
        for ( int i = pos + 1; i <= root ->n; i++) {
               root ->key[i - 1] = root ->key[i];
               root ->next[i - 1] = root ->next[i];
       }
        root ->next[ pos ] = node;
        root ->n -= 1;
        return ;
}
Node * erase_maintain( Node * root , int pos ) {
        //最少关键字数
        int lower_bound = ( MAX_M + 1) / 2 - 1;
        if ( root ->next[ pos ]->n >= lower_bound) return root ;
        // root->next[pos]左边关键字富裕
        if ( pos > 0 && root ->next[ pos - 1]->n > lower_bound) {
               //拎着pos - 1节点右旋
              right_rotate( root , pos - 1);
       }
        // root->next[pos]右边关键字富裕
        else if ( pos < root ->n && root ->next[ pos + 1]->n > lower_bound) {
               拎着pos节点左旋
              left_rotate( root , pos );
       }
        // root->next[pos]左右两边关键字都不富裕
        else {
               //pos > 0:向前合并
               if ( pos > 0) merge_node( root , pos - 1); // merge(i, j) -> (j, j + 1)
               //pos == 0 :向后合并
               else merge_node( root , pos );
       }
        return root ;
}
Node * __erase( Node * root , int key ) {
        if ( root == NULL ) return root ;
        int pos = 0;
        //找到大于或等于key的关键字的位置
        while (pos < root ->n && root ->key[pos] < key ) pos += 1;
        //当前节点为终端节点
        if ( root ->next[0] == NULL ) {
               if ( root ->key[pos] == key ) erase_pos( root , pos);
               return root ;
       }
        else {
               //找到key, 但不位于终端节点
               if (pos < root ->n && root ->key[pos] == key ) {
                       //查找key所在位置的前驱
                       //前驱位于终端节点
                       Node * temp = root ->next[pos];
                       while (temp->next[temp->n]) temp = temp->next[temp->n];
                       int val = temp->key[temp->n - 1];
                       //前驱与要删除位置交换-->把要删除的节点移到终端节点
                      swap( root ->key[pos], temp->key[temp->n - 1]);
              }
               //递归到终端节点删除key
               root ->next[pos] = __erase( root ->next[pos], key );
       }
        //pos为已删除关键字的分支
        return erase_maintain( root , pos);
}
Node * erase( Node * root , int key ) {
        root = __erase( root , key );
        //root的关键字数为0,将根节点的唯一子树作为新数根节点
        if ( root ->n == 0) {
               Node * temp = root ->next[0];
              free( root );
               root = temp;
       }
        return root ;
}
void clear( Node * root ) {
        if ( root == NULL ) return ;
        for ( int i = 0; i <= root ->n; i++) {
              clear( root ->next[i]);
       }
       free( root );
        return ;
}
void print_node( Node * root ) {
       printf( "%d : " , root ->n);
        for ( int i = 0; i < root ->n; i++) {
              printf( "%4d" , root ->key[i]);
       }
       printf( " | " );
        if ( root ->next[0] == NULL ) goto output_end;
        for ( int i = 0; i <= root ->n; i++) {
              printf( "%4d" , root ->next[i]->key[0]);
       }
output_end:
       printf( "\n" );
        return ;
}
void output( Node * root ) {
        if ( root == NULL ) return ;
       print_node( root );
        for ( int i = 0; i <= root ->n; i++) {
              output( root ->next[i]);
       }
        return ;
}
int main() {
       srand(time(0));
        Node * root = NULL ;
        for ( int i = 0; i < MAX_OP ; i++) {
               int val = rand() % 100;
              root = insert(root, val);
              printf( "\ninsert %d to BTree : \n" , val);
              output(root);
       }
        int x;
        while (~scanf_s( "%d" , &x)) {
              printf( "erase %d from BTree : \n" , x);
              root = erase(root, x);
              output(root);
       }
        return 0;
}
  • 22
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值