算法导论18章-B树

#include <stdio.h>
#include <malloc.h>

#define TRUE 1
#define FALSE 0

static int t = 2;

typedef struct _node node;

struct _node
{
    int    n;
    int   *key;//节点包含的key
    node  *c;//节点包含的孩子
    int    leaf;//是否为叶子
};

typedef struct _tree
{
    node *root;
} tree;

typedef struct _result
{
    node *x;
    int i;
} result;

void disk_read(node *x, int i)
{
    //
}

void disk_write(node *x)
{
    //
}
print_node(node *x)
{
    printf("n=%-3dkey1=%-3dkey2=%-3dkey3=%-3dc1=%p c2=%p c3=%p leaf=%d\n", x->n, x->key[1], x->key[2], x->key[3], x->c+1, x->c+2, x->c+3, x->leaf);
}
//搜索
result b_tree_search(node *x, int k)
{
    int i = 1;
    //移动指针到第一个不小于k的位置
    while(i <= x->n && k > x->key[i]){
        i++;
    }
   
    if(k == x->key[i]){//判断等于则返回
        result ret = {x,i};
        return ret;
    }else if(x->leaf){//叶子节点则返回
        result ret;
        return ret;
    }else{//内部节点
        disk_read(x, i);//读取x的c[i]孩子
        b_tree_search(x->c+i, k);//递归查找x->c+i节点
    }
}
//为新节点分配一个磁盘页
node * allocate_node()
{
    node *x = (node *)malloc(sizeof(node));
    x->key = (int *)malloc(sizeof(int) * 2 * t);//key分配内存
    x->c = (node *)malloc(sizeof(node) * (2 * t + 1));//孩子节点分配内存
    return x;
}
//分裂x->c+i节点
void b_tree_split_child(node *x, int i)
{
    node *z = allocate_node();
    node *y = x->c+i;
    int j = 0;
    z->leaf = y->leaf;
    z->n = t-1;
    //把y的t+1,...2t-1节点的key给z
    for(j = 1; j < t; j++){
        z->key[j] = y->key[t+j];
    }
    if(!y->leaf){//非叶子节点
        //把y的t+1,...2t的c节点给z
        for(j = 1; j <= t; j++){
            *(z->c+j) = *(y->c+t+j);
        }
    }
    y->n = t-1;
    //x节点增加z孩子;
    for(j = x->n+1; j > i; j--){
        *(x->c+j+1) = *(x->c+j);
    }
    *(x->c+i+1) = *z;
    //x节点插入y->key[t];
    for(j = x->n; j >= i; j--){
        x->key[j+1] = x->key[j];
    }
    x->key[i] = y->key[t];
    x->n = x->n + 1;
    // printf("\nsplit i x:");
    // print_node(x);
    // printf("y:");
    // print_node(y);
    // printf("z:");
    // print_node(z);
    disk_write(x);
    disk_write(y);
    disk_write(z);
}
//插入一个非满的b树
void b_tree_insert_nonfull(node *x, int k)
{
    int i = x->n;
    if(x->leaf){
        //找第一个不小于k的数
        while(i >= 1 && k < x->key[i]){
            x->key[i+1] = x->key[i];
            i--;
        }
        x->key[i+1] = k;
        x->n = x->n + 1;
        disk_write(x);
        // print_node(x);
    }else{//内部节点
        //找一个x的子节点i插入k
        while(i >= 1 && k < x->key[i]){
            i--;
        }
        i++;
        disk_read(x, i);
        if((x->c+i)->n == 2*t - 1){//即将插入的子节点满时则分裂
            b_tree_split_child(x, i);
            if(k > x->key[i]){//分裂后和新的i节点比较,大于则i指针加一
                i++;
            }
        }
        b_tree_insert_nonfull(x->c+i, k);//递归插入
    }
}
//插入
void b_tree_insert(tree *T, int k)
{
    node *r = T->root;
    if(r->n == 2*t - 1){//root满时分裂
        node *s = allocate_node();
        T->root = s;
        s->n = 0;
        s->leaf = FALSE;
        *(s->c+1) = *r;
        b_tree_split_child(s, 1);
        b_tree_insert_nonfull(s, k);
    }else{
        b_tree_insert_nonfull(r, k);
    }
}
//创建
void b_tree_create(tree *T)
{
    node *x = allocate_node();
    x->leaf = TRUE;
    x->n = 0;
    disk_write(x);
    T->root = x;
    // print_node(T->root);
}
//前驱
int b_tree_predecessor(node *x)
{
    //直接找到x的最右叶子节点
    while(!x->leaf){
        x = x->c+x->n+1;
    }
    return x->key[x->n];
}
//后继
int b_tree_successor(node *x)
{
    //直接找到x的最左叶子节点
    while(!x->leaf){
        x = x->c+1;
    }
    return x->key[1];
}
//合并两个节点
void b_tree_merge_node(node *x, node *y)
{
    int j;
    for(j = 1; j <= y->n; j++){
        x->key[x->n+j] = y->key[j];
    }
    if(!x->leaf){
        for(j = 1; j <= y->n+1; j++){
            *(x->c+x->n+j) = *(y->c+j);
        }
    }
    x->n += y->n;
    disk_write(x);
}
//直接删除一个key
void b_tree_delete_key(node *x, int i)
{
    int j;
    for(j = i; j < x->n; j++){
        x->key[j] = x->key[j+1];
    }
    if(!x->leaf){
        for(j = i+1; j <= x->n; j++){
            *(x->c+j) = *(x->c+j+1);
        }
    }
    x->n = x->n - 1;
    disk_write(x);
}
//删除
void b_tree_delete(tree *T, node *x, int k)
{
    int i = 1;
    //在x节点中移动i到一个不小于k的位置
    while(i <= x->n && x->key[i] < k){
        i++;
    }
    if(x->key[i] == k){//k在x中
        if(x->leaf){//x是叶子(情况1)
            //删除key[i]
            b_tree_delete_key(x, i);
        }else{//x非叶子(情况2)
            disk_read(x, i);
            disk_read(x, i+1);
            //至少含有t个关键字(情况2a)
            if((x->c+i)->n > t-1){
                //删除x->c+i中k的前驱,用前驱替换k
                x->key[i] = b_tree_predecessor(x->c+i);
                b_tree_delete(T, x->c+i, x->key[i]);
            }
            //x->c+i含有t-1个关键字,x->c[i+1]至少含有t个关键字(情况2b)
            else if((x->c+i+1)->n > t-1){
                //删除x->c[i+1]中k的后继,用后继替换k
                x->key[i] = b_tree_successor(x->c+i+1);
                b_tree_delete(T, x->c+i+1, x->key[i]);
            }
            //x->c+i和x->c[i+1]都含有t-1个关键字(情况2c)
            else{
                //合并x->c+i和x->c[i+1]
                b_tree_merge_node(x->c+i, x->c+i+1);
                //删除key[i]
                b_tree_delete_key(x, i);
                //当根节点被合并且为空节点
                if(x == T->root && x->n == 0){
                    T->root = x->c+i;
                }
            }
        }
    }else if(!x->leaf){//x不是叶子节点且k不在x中(情况3)
        disk_read(x, i);
        if((x->c+i)->n == t-1){//x->c+i含有t-1个关键字
            disk_read(x, i-1);
            disk_read(x, i+1);
            //x->c+i的相邻兄弟节点至少含有t个关键字(情况3a)
            if((x->c+i-1)->n >= t){
                //检查k是否在x->c+i-1中
                //x的key[i-1]下降到x->c+i[1]
                int j;
                for(j = (x->c+i)->n; j >= 1; j--){
                    (x->c+i)->key[j+1] = (x->c+i)->key[j];
                }
                (x->c+i)->key[j+1] = x->key[i-1];
                x->key[i-1] = (x->c+i-1)->key[(x->c+i-1)->n];
                if(!(x->c+i)->leaf){
                    for(j = (x->c+i)->n+1; j >= 1; j--){
                        *((x->c+i)->c+j+1) = *((x->c+i)->c+j);
                    }
                    //把x->c+i+1的最后一个孩子给x->c+i
                    *((x->c+i)->c+1) = *((x->c+i-1)->c+(x->c+i-1)->n+1);
                }
                (x->c+i)->n += 1;
                //删除k在左兄弟中的前驱
                b_tree_delete_key(x->c+i-1, (x->c+i-1)->n);
            }else if((x->c+i+1)->n >= t && i <= x->n){//i <= x->n条件避免使用已删除的节点
                //x的key[i]下降到(x->c+i)->key[n]
                (x->c+i)->key[(x->c+i)->n+1] = x->key[i];
                x->key[i] = (x->c+i+1)->key[1];
                if(!(x->c+i)->leaf){
                    //把x->c+i+1的第一个孩子给x->c+i
                    *((x->c+i)->c+(x->c+i)->n+2) = *((x->c+i+1)->c+1);
                }
                (x->c+i)->n += 1;
                //删除k在右兄弟中的后继
                *((x->c+i+1)->c+1) = *((x->c+i+1)->c+2);
                b_tree_delete_key(x->c+i+1, 1);
            }
            //x->c[i-1]和x->c[i+1]含有t-1个关键字(情况3b)
            else{
                //合并x->c[i-1]和x->c+i或者x->c+i和x->c[i+1]
                if(i > 1){//i有左兄弟,则指针前移
                    i = i - 1;
                }
                (x->c+i)->key[t] = x->key[i];
                (x->c+i)->n += 1;
                b_tree_merge_node(x->c+i, x->c+i+1);
                b_tree_delete_key(x, i);
                //当根节点被合并且为空节点
                if(x == T->root && x->n == 0){
                    T->root = x->c+i;
                }
            }
        }
        b_tree_delete(T, x->c+i, k);
    }
}
/**
 * 等分原理每个节点由父节点绝对占的线段,然后在这段线中间输出节点数据
 * --------1--------
 * ----1---1---1----
 * --1-1---1-1-1-1--
 */

void print_btree(node *x, int *A, int n, int m, int i, int s, int e)
{
    int j = s + (e - s)/2;//j定位到中间
    int k;
    for(k = 1; k <= x->n; k++){
        *(A + (i * m + (j - x->n/2 + k - 1))) = x->key[k];
    }
    if(!x->leaf){
        int b = (e - s)/(x->n+1);//把j-s的线段等分
        s = s - b;
        for(k = 1; k <= x->n+1; k++){
            s = s + b;
            e = s + b;
            if((s + e)/2 < j){
                *(A + ((i + 1) * m + ((s + e)/2 + j)/2)) = -2;
            }else if((s + e)/2 == j){
                *(A + ((i + 1) * m + ((s + e)/2 + j)/2)) = -3;
            }else{
                *(A + ((i + 1) * m + ((s + e)/2 + j)/2)) = -4;
            }
            print_btree(x->c+k, A, n, m, i+2, s, e);
            //print_btree(x->c+k, A, n, m, i+2, s+(k-1)*b, s+k*b);
        }
    }
    if(i == 0){//遍历输出
        int k;
        for(i = 0; i < n; i++){
            for(j = 0; j < m; j++){
                k =*(A + (i * m + j));
                if(k == 0){
                    printf(" ");
                }else if(k == -2){
                    printf("/");
                }else if(k == -3){
                    printf("|");
                }else if(k == -4){
                    printf("\\");
                }else{
                    printf("%c", k);
                }
            }
            printf("\n");
        }
    }
}
int main()
{
    char s[] = "FSQKCLHTVWMRNPABXYDZE";
    char d[] = "DTBCMP";
    tree *T = (tree *)malloc(sizeof(tree));
    b_tree_create(T);
    int i;
    printf("create tree\n");
    for(i = 0; i < sizeof(s) - 1; i++){
        // printf("insert:%-4d", (int)s[i]);
        b_tree_insert(T, (int)s[i]);
    }
    int *A;
    int n = 5,m = 64;
    A = (int *)malloc(sizeof(int) * n * m);
    print_btree(T->root, A, n, m, 0, 0, m);
   
    for(i = 0; i < sizeof(d) - 1; i++){
        printf("--------------------------------------------------------------------\n");
        printf("delete:%c\n", d[i]);
        b_tree_delete(T, T->root, (int)d[i]);
        A = (int *)malloc(sizeof(int) * n * m);
        print_btree(T->root, A, n, m, 0, 0, m);
    }
    printf("\n");
    return 0;
}

// create tree
//                                KQ                              
//                      /         /          \                    
//          BF                    M                   TW          
//       /   |  \              /    \              /   |  \        
//    A     CDE     H        L        NP       RS      V     XYZ  
// --------------------------------------------------------------------
// delete:D    情况1-D在叶子上
//                                KQ                              
//                      /         /          \                    
//          BF                    M                   TW          
//       /   |  \              /    \              /   |  \        
//    A     CE      H        L        NP       RS      V     XYZ  
// --------------------------------------------------------------------
// delete:T    情况2a-T在内部节点上,且左孩子的n>t
//                                KQ                              
//                      /         /          \                    
//          BF                    M                   SW          
//       /   |  \              /    \              /   |  \        
//    A     CE      H        L        NP        R      V     XYZ  
// --------------------------------------------------------------------
// delete:B    情况2b-B在内部节点上,且右孩子的n>t
//                                KQ                              
//                      /         /          \                    
//          CF                    M                   SW          
//       /   |  \              /    \              /   |  \        
//    A      E      H        L        NP        R      V     XYZ  
// --------------------------------------------------------------------
// delete:C    情况2c-C在内部节点上,且左右孩子n=t-1
//                                KQ                              
//                      /         /          \                    
//           F                    M                   SW          
//        /    \               /    \              /   |  \        
//     AE         H          L        NP        R      V     XYZ  
// --------------------------------------------------------------------  
// delete:M    情况3a-M在内部节点上,且右兄弟n>=t
//                                KS                              
//                      /         /          \                    
//           F                   NQ                    W          
//        /    \              /   |  \              /    \        
//     AE         H        L      P      R        V        XYZ    
// --------------------------------------------------------------------
// delete:P    情况3b-P在页节点上,且左右兄弟n=t-1
//                                KS                              
//                      /         /          \                    
//           F                    Q                    W          
//        /    \               /    \               /    \        
//     AE         H         LN         R          V        XYZ

转载请注明:小Y » 算法导论18章-B树

赞 (0) 评论 (0) 分享 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址