1.3 B树 学习笔记

参考:零声学院课程

一颗M阶B树T,满足以下条件

1. 每个结点至多拥有M棵子树

2. 根结点至少拥有两颗子树

3. 除了根结点以外,其余每个分支结点至少拥有M/2棵子树

4. 所有的叶结点都在同一层上

5. 有k课子树的分支结点则存在k-1个关键字,关键字按照递增顺序进行排序

6. 关键字数量满足ceil(M/2)-1 <= n <= M-1

B树通过分裂,得到新结点

B树通过合并,减少结点

新增key,都是加在叶子节点里;同时递归过程中需要判断子树key是不是M-1,并分裂子树

删除key,通过借或者合并,使得要删除的key落在叶子节点里;同时递归过程中需要判断子树key是不是<=ceil(m/2)-1,然后借或者合并子树

#include <stdio.h>
#include <stdlib.h>


/*
一颗M阶B树T,满足以下条件
1. 每个结点至多拥有M棵子树
2. 根结点至少拥有两颗子树
3. 除了根结点以外,其余每个分支结点至少拥有M/2棵子树
4. 所有的叶结点都在同一层上
5. 有k课子树的分支结点则存在k-1个关键字,关键字按照递增顺序进行排序
6. 关键字数量满足ceil(M/2)-1 <= n <= M-1
*/

#define ceil(M) ((M-1)/2)

typedef int KEY_VALUE;

struct btree_node{
    KEY_VALUE *keys;
    struct btree_node **children;
    int num;
    int leaf;//1 leaf ; 0 not leaf
};

struct btree_node* btree_node_create(int m,int leaf){
    struct btree_node *node = malloc(sizeof(struct btree_node));
    node->keys = malloc(sizeof(KEY_VALUE) * (m));//merge的时候,会出现刚好是m的情况
    node->children = malloc(sizeof(struct btree_node*) * (m+1));
    node->num = 0;
    node->leaf = leaf;
    int i;
    for(i=0;i<m+1;i++)
        node->children[i] = NULL;
    return node;
}

void btree_node_destroy(struct btree_node *node){
    free(node->keys);
    free(node->children);
    free(node);
}


typedef struct{
    struct btree_node *root;
    int m;//表示m阶
    int ceil_m;
}btree;


btree* btree_create(int m){
    btree *T = malloc(sizeof(btree));
    T->root = btree_node_create(m,1);
    T->m = m;
    T->ceil_m = ceil(m);
    return T;
}

void btree_split_child(btree* T,struct btree_node *node,int idx){
    struct btree_node *x = node->children[idx];
    struct btree_node *y = btree_node_create(T->m,x->leaf);
    int i,j;
    for(i=T->ceil_m+1,j=0;i<x->num;i++,j++){
        y->keys[j] = x->keys[i];
    }

    for(i=T->ceil_m+1,j=0;i<=x->num;i++,j++){
        y->children[j] = x->children[i];
    }
    y->num = x->num -T->ceil_m -1;
    x->num = T->ceil_m;
    
    
    for(i=node->num-1;i>=idx;i--){
        node->keys[i+1] = node->keys[i];
    }
    node->keys[i+1] = x->keys[T->ceil_m];

    for(i=node->num;i>=idx+1;i--){
        node->children[i+1] = node->children[i];
    }
    node->children[i+1] = y;

    node->num++;
}


void btree_insert_nonfull(btree *T,struct btree_node* node,KEY_VALUE key){
    int i,j;
    for(i=0;i<node->num&&key>node->keys[i];i++){}

    if(i<node->num && key == node->keys[i]){
        return;
    }
    if(node->leaf==1){
        for(j=node->num-1;j>=i;j--){
            node->keys[j+1] = node->keys[j];
        }
        node->keys[j+1] = key;
        node->num++;
    }else{
        if(node->children[i]->num == T->m-1){
            btree_split_child(T,node,i);
            if(key == node->keys[i])
                return;
            else if(key > node->keys[i])
                i++;
        }
        btree_insert_nonfull(T,node->children[i],key);
    }
}

void btree_insert(btree* T,KEY_VALUE key){
    if(T->root->num >= T->m-1){
        struct btree_node *node = btree_node_create(T->m,0);
        node->children[0] = T->root;
        T->root = node;
        btree_split_child(T,T->root,0);
    }

    btree_insert_nonfull(T,T->root,key);
}

void btree_merge(btree* T,struct btree_node *node,int idx){
    struct btree_node *x = node->children[idx];
    struct btree_node *y = node->children[idx+1];
    int i,j;
    x->keys[x->num] = node->keys[idx];
    for(i=x->num+1,j=0;j<y->num;i++,j++){
        x->keys[i] = y->keys[j];
    }
    for(i=x->num+1,j=0;j<=y->num;i++,j++){
        x->children[i] = y->children[j];
    }
    x->num += (1 + y->num);
    btree_node_destroy(y);

    for(i=idx;i<node->num-1;i++){
        node->keys[i] = node->keys[i+1];
    }

    for(i=idx+1;i<node->num;i++){
        node->children[i] = node->children[i+1];
    }
    node->num--;
    if(node->num == 0){
        T->root = x;
        btree_node_destroy(node);
    }
}

void btree_delete_node(btree* T,struct btree_node *node, KEY_VALUE key){
    if(node == NULL)
        return;
    int idx,i;
    for(idx=0;idx<node->num&&key>node->keys[idx];idx++){}
    if(idx<node->num && key == node->keys[idx]){
        if(node->leaf == 1){
            for(i=idx;i<node->num-1;i++){
                node->keys[i] = node->keys[i+1];
            }
            node->num--;
            if(node->num == 0){//root

            }
            return;
        }else if(node->children[idx]->num > T->ceil_m){
            struct btree_node *left = node->children[idx];
            node->keys[idx] = left->keys[left->num-1];
            btree_delete_node(T,left,left->keys[left->num-1]);
        }else if(node->children[idx+1]->num > T->ceil_m){
            struct btree_node *right = node->children[idx+1];
            node->keys[idx] = right->keys[0];
            btree_delete_node(T,right,right->keys[0]);
        }else{
            int flag = (node == T->root);
            btree_merge(T,node,idx);
            if(flag && node != T->root){
                btree_delete_node(T,T->root,key);    
            }else{
                btree_delete_node(T,node->children[idx],key);
            }
        }
    }else{
        struct btree_node *child = node->children[idx];

		if(child == NULL){
			return ;
		}

        if(child->num<= T->ceil_m){
            struct btree_node *left=NULL,*right=NULL;
            if(idx-1>=0)
                left = node->children[idx-1];
            if(idx+1<=node->num)
                right = node->children[idx+1];
            if(left != NULL && left->num > T->ceil_m || 
                right != NULL && right->num > T->ceil_m){
                
                int richR = 0;
                if(right!=NULL)
                    richR = 1;
                if(left!=NULL&&right!=NULL)
                    richR = right->num>left->num?1:0;
                if(right!=NULL&&right->num>T->ceil_m&&richR){//borrow from right
                    child->keys[child->num] = node->keys[idx];
                    child->children[child->num+1] = right->children[0];
                    child->num++;

                    node->keys[idx] = right->keys[0];
                    for(i=0;i<right->num-1;i++){
                        right->keys[i] = right->keys[i+1];
                    }
                    for(i=0;i<right->num;i++){
                        right->children[i] = right->children[i+1];
                    }
                    right->num--;
                }else{//borrow from left
                    for(i=child->num-1;i>=0;i--){
                        child->keys[i+1] = child->keys[i];
                    }
                    for(i=child->num;i>=0;i--){
                        child->children[i+1] = child->children[i];
                    }
                    child->keys[0] = node->keys[idx-1];
                    child->children[0] = left->children[left->num];
                    child->num++;

                    node->keys[idx-1] = left->keys[left->num-1];
                    left->num--;
                }
            }else if((left==NULL || left->num<=T->ceil_m) && (right==NULL || right->num<=T->ceil_m)){
                if(left != NULL && left->num<=T->ceil_m){
                    btree_merge(T,node,idx-1);
                    child = left;
                }else if(right!=NULL && right->num<=T->ceil_m){
                    btree_merge(T,node,idx);
                }
            }
            
        }
        btree_delete_node(T,child,key);
    }
}



void btree_delete(btree* T,KEY_VALUE key){
    btree_delete_node(T,T->root,key);
}

void btree_traverse(struct btree_node *node){
    if(node == NULL)
        return;
    int i;
    printf("[");
    for(i=0;i<node->num;i++){
        //btree_traverse(node->children[i]);
		printf("%d, ",node->keys[i]);
    }
    printf("], ");
    for(i=0;i<=node->num;i++){
        btree_traverse(node->children[i]);
		//printf("%d, ",node->keys[i]);
    }
    //btree_traverse(node->children[i]);
    
}

int main(){
    btree *T = btree_create(5);
    int i;
    btree_insert(T,0);
    btree_insert(T,1);
    btree_insert(T,3);
    btree_insert(T,4);
    btree_insert(T,5);

    btree_traverse(T->root);printf("\n");

    btree_delete(T,2);
    btree_traverse(T->root);printf("\n");

	btree_delete(T,3);
    btree_traverse(T->root);printf("\n");

    btree_insert(T,2);
    btree_traverse(T->root);printf("\n");

	btree_insert(T,3);
    btree_traverse(T->root);printf("\n");

	btree_delete(T,5);
    btree_traverse(T->root);printf("\n");
}

猜你喜欢

转载自blog.csdn.net/ZRXSLYG/article/details/113148603
1.3