B树算法与实现 (C语言实现)

B树的定义

假设B树的度为t(t>=2),则B树满足如下要求:(参考算法导论)

(1)  每个非根节点至少包含t-1个关键字,t个指向子节点的指针;至多包含2t-1个关键字,2t个指向子女的指针(叶子节点的子女为空)。

(2)  节点的所有key按非降序存放,假设节点的关键字分别为K[1], K[2] … K[n], 指向子女的指针分别为P[1], P[2]…P[n+1],其中n为节点关键字的个数。则有:

P[1] <= K[1] <= P[2] <= K[2] …..<= K[n] <= P[n+1]   // 这里P[n]也指其指向的关键字

(3)  若根节点非空,则根节点至少包含两个子女;

(4)  所有的叶子节点都在同一层。

 

B树的搜索,searchroot, target

从root出发,对每个节点,找到大于或等于target关键字中最小的K[i],如果K[i]与target相等,则查找成功;否则在P[i]中递归搜索target,直到到达叶子节点,如仍未找到则说明关键字不在B树中,查找失败。

B树的插入,insert(root, target)

B树的插入需要沿着搜索的路径从root一直到叶节点,根据B树的规则,每个节点的关键字个数在[t-1, 2t-1]之间,故当target要加入到某个叶子时,如果该叶子节点已经有2t-1个关键字,则再加入target就违反了B树的定义,这时就需要对该叶子节点进行分裂,将叶子以中间节点为界,分成两个包含t-1个关键字的子节点,同时把中间节点提升到该叶子的父节点中,如果这样使得父节点的关键字个数超过2t-1,则要继续向上分裂,直到根节点,根节点的分裂会使得树加高一层。

上面的过程需要回溯,那么能否从根下降到叶节点后不回溯就能完成节点的插入呢?答案是肯定的,核心思想就是未雨绸缪,在下降的过程中,一旦遇到已满的节点(关键字个数为2t-1),就就对该节点进行分裂,这样就保证在叶子节点需要分裂时,其父节点一定是非满的,从而不需要再向上回溯。

B树的删除,delete(root, target)

在删除B树节点时,为了避免回溯,当遇到需要合并的节点时就立即执行合并,B树的删除算法如下:从root向叶子节点按照search规律遍历:

(1)  如果target在叶节点x中,则直接从x中删除target,情况(2)和(3)会保证当再叶子节点找到target时,肯定能借节点或合并成功而不会引起父节点的关键字个数少于t-1。

(2)  如果target在分支节点x中:

(a)  如果x的左分支节点y至少包含t个关键字,则找出y的最右的关键字prev,并替换target,并在y中递归删除prev。

(b)  如果x的右分支节点z至少包含t个关键字,则找出z的最左的关键字next,并替换target,并在z中递归删除next。

(c)  否则,如果y和z都只有t-1个关键字,则将targe与z合并到y中,使得y有2t-1个关键字,再从y中递归删除target。

(3)  如果关键字不在分支节点x中,则必然在x的某个分支节点p[i]中,如果p[i]节点只有t-1个关键字。

(a)  如果p[i-1]拥有至少t个关键字,则将x的某个关键字降至p[i]中,将p[i-1]的最大节点上升至x中。

(b)  如果p[i+1]拥有至少t个关键字,则将x个某个关键字降至p[i]中,将p[i+1]的最小关键字上升至x个。

(c)  如果p[i-1]与p[i+1]都拥有t-1个关键字,则将p[i]与其中一个兄弟合并,将x的一个关键字降至合并的节点中,成为中间关键字。

btree.c

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

/**
 * @brief the degree of btree
 * key per node: [M-1, 2M-1]
 * child per node: [M, 2M]
 */
#define M 2

typedef struct btree_node {
    int k[2*M-1];
    struct btree_node *p[2*M];
    int num;
    bool is_leaf;
} btree_node;

/**
 * @brief allocate a new btree node
 * default: is_leaf == true
 *
 * @return pointer of new node
 */
btree_node *btree_node_new();

/**
 * @brief create a btree root
 *
 * @return pointer of btree root
 */
btree_node *btree_create();

/**
 * @brief split child if num of key in child exceed 2M-1
 *
 * @param parent: parent of child
 * @param pos: p[pos] points to child
 * @param child: the node to be splited
 *
 * @return
 */
int btree_split_child(btree_node *parent, int pos, btree_node *child);

/**
 * @brief insert a value into btree
 * the num of key in node less than 2M-1
 *
 * @param node: tree root
 * @param target: target to insert
 */
void btree_insert_nonfull(btree_node *node, int target);

/**
 * @brief insert a value into btree

 *
 * @param root: tree root
 * @param target: target to insert
 *
 * @return: new root of tree
 */
btree_node* btree_insert(btree_node *root, int target);

/**
 * @brief merge y, z and root->k[pos] to left
 * this appens while y and z both have M-1 keys
 *
 * @param root: parent node
 * @param pos: postion of y
 * @param y: left node to merge
 * @param z: right node to merge
 */
void btree_merge_child(btree_node *root, int pos, btree_node *y, btree_node *z);

/**
 * @brief delete a vlue from btree
 *
 * @param root: btree root
 * @param target: target to delete
 *
 * @return: new root of tree
 */
btree_node *btree_delete(btree_node *root, int target);

/**
 * @brief delete a vlue from btree
 * root has at least M keys
 *
 * @param root: btree root
 * @param target: target to delete
 *
 * @return
 */
void btree_delete_nonone(btree_node *root, int target);

/**
 * @brief find the rightmost value
 *
 * @param root: root of tree
 *
 * @return: the rightmost value
 */
int btree_search_predecessor(btree_node *root);

/**
 * @brief find the leftmost value
 *
 * @param root: root of tree
 *
 * @return: the leftmost value
 */
int btree_search_successor(btree_node *root);

/**
 * @brief shift a value from z to y
 *
 * @param root: btree root
 * @param pos: position of y
 * @param y: left node
 * @param z: right node
 */
void btree_shift_to_left_child(btree_node *root, int pos, btree_node *y, btree_node *z);

/**
 * @brief shift a value from z to y
 *
 * @param root: btree root
 * @param pos: position of y
 * @param y: left node
 * @param z: right node
 */
void btree_shift_to_right_child(btree_node *root, int pos, btree_node *y, btree_node *z);

/**
 * @brief inorder traverse the btree
 *
 * @param root: root of treee
 */
void btree_inorder_print(btree_node *root);

/**
 * @brief level print the btree
 *
 * @param root: root of tree
 */
void btree_level_display(btree_node *root);

btree_node *btree_node_new()
{
    btree_node *node = (btree_node *)malloc(sizeof(btree_node));
    if(NULL == node) {
        return NULL;
    }

    for(int i = 0; i < 2 * M -1; i++) {
        node->k[i] = 0;
    }

    for(int i = 0; i < 2 * M; i++) {
        node->p[i] = NULL;
    }

    node->num = 0;
    node->is_leaf = true;
}

btree_node *btree_create()
{
    btree_node *node = btree_node_new();
    if(NULL == node) {
        return NULL;
    }

    return node;
}

int btree_split_child(btree_node *parent, int pos, btree_node *child)
{
    btree_node *new_child = btree_node_new();
    if(NULL == new_child) {
        return -1;
    }

    new_child->is_leaf = child->is_leaf;
    new_child->num = M - 1;

    for(int i = 0; i < M - 1; i++) {
        new_child->k[i] = child->k[i+M];
    }

    if(false == new_child->is_leaf) {
        for(int i = 0; i < M; i++) {
            new_child->p[i] = child->p[i+M];
        }
    }

    child->num = M - 1;

    for(int i = parent->num; i > pos; i--) {
        parent->p[i+1] = parent->p[i];
    }
    parent->p[pos+1] = new_child;

    for(int i = parent->num - 1; i >= pos; i--) {
        parent->k[i+1] = parent->k[i];
    }
    parent->k[pos] = child->k[M-1];

    parent->num += 1;
}

void btree_insert_nonfull(btree_node *node, int target)
{
    if(1 == node->is_leaf) {
        int pos = node->num;
        while(pos >= 1 && target < node->k[pos-1]) {
            node->k[pos] = node->k[pos-1];
            pos--;
        }

        node->k[pos] = target;
        node->num += 1;

    } else {
        int pos = node->num;
        while(pos > 0 && target < node->k[pos-1]) {
            pos--;
        }

        if(2 * M -1 == node->p[pos]->num) {
            btree_split_child(node, pos, node->p[pos]);
            if(target > node->k[pos]) {
                pos++;
            }
        }

        btree_insert_nonfull(node->p[pos], target);
    }
}

btree_node* btree_insert(btree_node *root, int target)
{
    if(NULL == root) {
        return NULL;
    }

    if(2 * M - 1 == root->num) {
        btree_node *node = btree_node_new();
        if(NULL == node) {
            return root;
        }

        node->is_leaf = 0;
        node->p[0] = root;
        btree_split_child(node, 0, root);
        btree_insert_nonfull(node, target);
        return node;
    } else {
        btree_insert_nonfull(root, target);
        return root;
    }
}

void btree_merge_child(btree_node *root, int pos, btree_node *y, btree_node *z)
{
    y->num = 2 * M - 1;
    for(int i = M; i < 2 * M - 1; i++) {
        y->k[i] = z->k[i-M];
    }
    y->k[M-1] = root->k[pos];

    if(false == z->is_leaf) {
        for(int i = M; i < 2 * M; i++) {
            y->p[i] = z->p[i-M];
        }
    }

    for(int j = pos + 1; j < root->num; j++) {
        root->k[j-1] = root->k[j];
        root->p[j] = root->p[j+1];
    }

    root->num -= 1;
    free(z);
}

btree_node *btree_delete(btree_node *root, int target)
{
    if(1 == root->num) {
        btree_node *y = root->p[0];
        btree_node *z = root->p[1];
        if(NULL != y && NULL != z &&
                M - 1 == y->num && M - 1 == z->num) {
            btree_merge_child(root, 0, y, z);
            free(root);
            btree_delete_nonone(y, target);
            return y;
        } else {
            btree_delete_nonone(root, target);
            return root;
        }
    } else {
        btree_delete_nonone(root, target);
        return root;
    }
}

void btree_delete_nonone(btree_node *root, int target)
{
    if(true == root->is_leaf) {
        int i = 0;
        while(i < root->num && target > root->k[i]) i++;
        if(target == root->k[i]) {
            for(int j = i + 1; j < 2 * M - 1; j++) {
                root->k[j-1] = root->k[j];
            }
            root->num -= 1;
        } else {
            printf("target not found\n");
        }
    } else {
        int i = 0;
        btree_node *y = NULL, *z = NULL;
        while(i < root->num && target > root->k[i]) i++;
        if(i < root->num && target == root->k[i]) {
            y = root->p[i];
            z = root->p[i+1];
            if(y->num > M - 1) {
                int pre = btree_search_predecessor(y);
                root->k[i] = pre;
                btree_delete_nonone(y, pre);
            } else if(z->num > M - 1) {
                int next = btree_search_successor(z);
                root->k[i] = next;
                btree_delete_nonone(z, next);
            } else {
                btree_merge_child(root, i, y, z);
                btree_delete(y, target);
            }
        } else {
            y = root->p[i];
            if(i < root->num) {
                z = root->p[i+1];
            }
            btree_node *p = NULL;
            if(i > 0) {
                p = root->p[i-1];
            }

            if(y->num == M - 1) {
                if(i > 0 && p->num > M - 1) {
                    btree_shift_to_right_child(root, i-1, p, y);
                } else if(i < root->num && z->num > M - 1) {
                    btree_shift_to_left_child(root, i, y, z);
                } else if(i > 0) {
                    btree_merge_child(root, i-1, p, y); // note
                    y = p;
                } else {
                    btree_merge_child(root, i, y, z);
                }
                btree_delete_nonone(y, target);
            } else {
                btree_delete_nonone(y, target);
            }
        }

    }
}

int btree_search_predecessor(btree_node *root)
{
    btree_node *y = root;
    while(false == y->is_leaf) {
        y = y->p[y->num];
    }
    return y->k[y->num-1];
}

int btree_search_successor(btree_node *root)
{
    btree_node *z = root;
    while(false == z->is_leaf) {
        z = z->p[0];
    }
    return z->k[0];
}

void btree_shift_to_right_child(btree_node *root, int pos,
        btree_node *y, btree_node *z)
{
    z->num += 1;
    for(int i = z->num -1; i > 0; i--) {
        z->k[i] = z->k[i-1];
    }
    z->k[0]= root->k[pos];
    root->k[pos] = y->k[y->num-1];

    if(false == z->is_leaf) {
        for(int i = z->num; i > 0; i--) {
            z->p[i] = z->p[i-1];
        }
        z->p[0] = y->p[y->num];
    }

    y->num -= 1;
}

void btree_shift_to_left_child(btree_node *root, int pos,
        btree_node *y, btree_node *z)
{
    y->num += 1;
    y->k[y->num-1] = root->k[pos];
    root->k[pos] = z->k[0];

    for(int j = 1; j < z->num; j++) {
        z->k[j-1] = z->k[j];
    }

    if(false == z->is_leaf) {
        y->p[y->num] = z->p[0];
        for(int j = 1; j <= z->num; j++) {
            z->p[j-1] = z->p[j];
        }
    } 

    z->num -= 1;
}

void btree_inorder_print(btree_node *root)
{
    if(NULL != root) {
        btree_inorder_print(root->p[0]);
        for(int i = 0; i < root->num; i++) {
            printf("%d ", root->k[i]);
            btree_inorder_print(root->p[i+1]);
        }
    }
}

void btree_level_display(btree_node *root)
{
    // just for simplicty, can‘t exceed 200 nodes in the tree
    btree_node *queue[200] = {NULL};
    int front = 0;
    int rear = 0;

    queue[rear++] = root;

    while(front < rear) {
        btree_node *node = queue[front++];

        printf("[");
        for(int i = 0; i < node->num; i++) {
            printf("%d ", node->k[i]);
        }
        printf("]");

        for(int i = 0; i <= node->num; i++) {
            if(NULL != node->p[i]) {
                queue[rear++] = node->p[i];
            }
        }
    }
    printf("\n");
}

int main()
{
    int arr[] = {18, 31, 12, 10, 15, 48, 45, 47, 50, 52, 23, 30, 20};

    btree_node *root = btree_create();

    for(int i = 0; i < sizeof(arr) / sizeof(int); i++) {
        root = btree_insert(root, arr[i]);
        btree_level_display(root);
    }

    //int todel[] = {15, 18, 23, 30, 31, 52, 50};
    int todel[] = {52};
    for(int i = 0; i < sizeof(todel) / sizeof(int); i++) {
        printf("after delete %d\n", todel[i]);
        root = btree_delete(root, todel[i]);
        btree_level_display(root);
    } 

    return 0;
}

B+

与B树不同的时,B+树的关键字都存储在叶子节点,分支节点均为索引,在实现上大致与B树类似,在几个细节稍有不同。

(1) 数据结构中增加prev,next指针,用于将叶子节点串成有序双向链表。

(2) 在节点分裂的时候,如果分裂的节点为叶子,则需要把中间节点保留在左(或右)边的分支上,并且需要更新prev和next。

(3) 在节点合的时候,如果合并的节点为叶子,不需要把跟节点下降为中间节点,并且需要更新prev和next。

(4) 在向邻接节点借节点时,借来的关键字并不是父节点的关键字,而是邻接点的关键字,并根据实际情况更新父节点的索引。

bplustree.c

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

/**
 * @brief the degree of btree
 * key per node: [M-1, 2M-1]
 * child per node: [M, 2M]
 */
#define M 2  // the degree of btree

typedef struct btree_node {
    int k[2*M-1];
    struct btree_node *p[2*M];
    int num;
    bool is_leaf;
    struct btree_node *prev;  // use one struct just for simple
    struct btree_node *next;
} btree_node;

/**
 * @brief allocate a new btree node
 * default: is_leaf == true
 *
 * @return pointer of new node
 */
btree_node *btree_node_new();

/**
 * @brief create a btree root
 *
 * @return pointer of btree root
 */
btree_node *btree_create();

/**
 * @brief split child if num of key in child exceed 2M-1
 *
 * @param parent: parent of child
 * @param pos: p[pos] points to child
 * @param child: the node to be splited
 *
 * @return
 */
int btree_split_child(btree_node *parent, int pos, btree_node *child);

/**
 * @brief insert a value into btree
 * the num of key in node less than 2M-1
 *
 * @param node: tree root
 * @param target: target to insert
 */
void btree_insert_nonfull(btree_node *node, int target);

/**
 * @brief insert a value into btree

 *
 * @param root: tree root
 * @param target: target to insert
 *
 * @return: new root of tree
 */
btree_node* btree_insert(btree_node *root, int target);

/**
 * @brief merge y, z and root->k[pos] to left
 * this appens while y and z both have M-1 keys
 *
 * @param root: parent node
 * @param pos: postion of y
 * @param y: left node to merge
 * @param z: right node to merge
 */
void btree_merge_child(btree_node *root, int pos, btree_node *y, btree_node *z);

/**
 * @brief delete a vlue from btree
 *
 * @param root: btree root
 * @param target: target to delete
 *
 * @return: new root of tree
 */
btree_node *btree_delete(btree_node *root, int target);

/**
 * @brief delete a vlue from btree
 * root has at least M keys
 *
 * @param root: btree root
 * @param target: target to delete
 *
 * @return
 */
void btree_delete_nonone(btree_node *root, int target);

/**
 * @brief find the rightmost value
 *
 * @param root: root of tree
 *
 * @return: the rightmost value
 */
int btree_search_predecessor(btree_node *root);

/**
 * @brief find the leftmost value
 *
 * @param root: root of tree
 *
 * @return: the leftmost value
 */
int btree_search_successor(btree_node *root);

/**
 * @brief shift a value from z to y
 *
 * @param root: btree root
 * @param pos: position of y
 * @param y: left node
 * @param z: right node
 */
void btree_shift_to_left_child(btree_node *root, int pos, btree_node *y, btree_node *z);

/**
 * @brief shift a value from z to y
 *
 * @param root: btree root
 * @param pos: position of y
 * @param y: left node
 * @param z: right node
 */
void btree_shift_to_right_child(btree_node *root, int pos, btree_node *y, btree_node *z);

/**
 * @brief inorder traverse the btree
 *
 * @param root: root of treee
 */
void btree_inorder_print(btree_node *root);

/**
 * @brief print tree linearly using prev/next pointer
 *
 * @param root: root of tree
 */
void btree_linear_print(btree_node *root);

/**
 * @brief level print the btree
 *
 * @param root: root of tree
 */
void btree_level_display(btree_node *root);

btree_node *btree_node_new()
{
    btree_node *node = (btree_node *)malloc(sizeof(btree_node));
    if(NULL == node) {
        return NULL;
    }

    for(int i = 0; i < 2 * M -1; i++) {
        node->k[i] = 0;
    }

    for(int i = 0; i < 2 * M; i++) {
        node->p[i] = NULL;
    }

    node->num = 0;
    node->is_leaf = true;
    node->prev = NULL;
    node->next = NULL;
}

btree_node *btree_create()
{
    btree_node *node = btree_node_new();
    if(NULL == node) {
        return NULL;
    }

    node->next = node;
    node->prev = node;

    return node;
}

int btree_split_child(btree_node *parent, int pos, btree_node *child)
{
    btree_node *new_child = btree_node_new();
    if(NULL == new_child) {
        return -1;
    }

    new_child->is_leaf = child->is_leaf;
    new_child->num = M - 1;

    for(int i = 0; i < M - 1; i++) {
        new_child->k[i] = child->k[i+M];
    }

    if(false == new_child->is_leaf) {
        for(int i = 0; i < M; i++) {
            new_child->p[i] = child->p[i+M];
        }
    }

    child->num = M - 1;
    if(true == child->is_leaf) {
        child->num++;  // if leaf, keep the middle ele, put it in the left
    }

    for(int i = parent->num; i > pos; i--) {
        parent->p[i+1] = parent->p[i];
    }
    parent->p[pos+1] = new_child;

    for(int i = parent->num - 1; i >= pos; i--) {
        parent->k[i+1] = parent->k[i];
    }
    parent->k[pos] = child->k[M-1];

    parent->num += 1;

    // update link
    if(true == child->is_leaf) {
        new_child->next = child->next;
        child->next->prev = new_child;
        new_child->prev = child;
        child->next = new_child;
    }
}

void btree_insert_nonfull(btree_node *node, int target)
{
    if(1 == node->is_leaf) {
        int pos = node->num;
        while(pos >= 1 && target < node->k[pos-1]) {
            node->k[pos] = node->k[pos-1];
            pos--;
        }

        node->k[pos] = target;
        node->num += 1;

    } else {
        int pos = node->num;
        while(pos > 0 && target < node->k[pos-1]) {
            pos--;
        }

        if(2 * M -1 == node->p[pos]->num) {
            btree_split_child(node, pos, node->p[pos]);
            if(target > node->k[pos]) {
                pos++;
            }
        }

        btree_insert_nonfull(node->p[pos], target);
    }
}

btree_node* btree_insert(btree_node *root, int target)
{
    if(NULL == root) {
        return NULL;
    }

    if(2 * M - 1 == root->num) {
        btree_node *node = btree_node_new();
        if(NULL == node) {
            return root;
        }

        node->is_leaf = 0;
        node->p[0] = root;
        btree_split_child(node, 0, root);
        btree_insert_nonfull(node, target);
        return node;
    } else {
        btree_insert_nonfull(root, target);
        return root;
    }
}

void btree_merge_child(btree_node *root, int pos, btree_node *y, btree_node *z)
{
    if(true == y->is_leaf) {
        y->num = 2 * M - 2;
        for(int i = M; i < 2 * M - 1; i++) {
            y->k[i-1] = z->k[i-M];
        }
    } else {
        y->num = 2 * M - 1;
        for(int i = M; i < 2 * M - 1; i++) {
            y->k[i] = z->k[i-M];
        }
        y->k[M-1] = root->k[pos];
        for(int i = M; i < 2 * M; i++) {
            y->p[i] = z->p[i-M];
        }
    }

    for(int j = pos + 1; j < root->num; j++) {
        root->k[j-1] = root->k[j];
        root->p[j] = root->p[j+1];
    }

    root->num -= 1;

    // update link
    if(true == y->is_leaf) {
        y->next = z->next;
        z->next->prev = y;
    }

    free(z);
}

btree_node *btree_delete(btree_node *root, int target)
{
    if(1 == root->num) {
        btree_node *y = root->p[0];
        btree_node *z = root->p[1];
        if(NULL != y && NULL != z &&
                M - 1 == y->num && M - 1 == z->num) {
            btree_merge_child(root, 0, y, z);
            free(root);
            btree_delete_nonone(y, target);
            return y;
        } else {
            btree_delete_nonone(root, target);
            return root;
        }
    } else {
        btree_delete_nonone(root, target);
        return root;
    }
}

void btree_delete_nonone(btree_node *root, int target)
{
    if(true == root->is_leaf) {
        int i = 0;
        while(i < root->num && target > root->k[i]) i++;
        if(target == root->k[i]) {
            for(int j = i + 1; j < 2 * M - 1; j++) {
                root->k[j-1] = root->k[j];
            }
            root->num -= 1;
        } else {
            printf("target not found\n");
        }
    } else {
        int i = 0;
        btree_node *y = NULL, *z = NULL;
        while(i < root->num && target > root->k[i]) i++;

        y = root->p[i];
        if(i < root->num) {
            z = root->p[i+1];
        }
        btree_node *p = NULL;
        if(i > 0) {
            p = root->p[i-1];
        }

        if(y->num == M - 1) {
            if(i > 0 && p->num > M - 1) {
                btree_shift_to_right_child(root, i-1, p, y);
            } else if(i < root->num && z->num > M - 1) {
                btree_shift_to_left_child(root, i, y, z);
            } else if(i > 0) {
                btree_merge_child(root, i-1, p, y);
                y = p;
            } else {
                btree_merge_child(root, i, y, z);
            }
            btree_delete_nonone(y, target);
        } else {
            btree_delete_nonone(y, target);
        }
    }
}

int btree_search_predecessor(btree_node *root)
{
    btree_node *y = root;
    while(false == y->is_leaf) {
        y = y->p[y->num];
    }
    return y->k[y->num-1];
}

int btree_search_successor(btree_node *root)
{
    btree_node *z = root;
    while(false == z->is_leaf) {
        z = z->p[0];
    }
    return z->k[0];
}

void btree_shift_to_right_child(btree_node *root, int pos,
        btree_node *y, btree_node *z)
{
    z->num += 1;

    if(false == z->is_leaf) {
        z->k[0] = root->k[pos];
        root->k[pos] = y->k[y->num-1];
    } else {
        z->k[0] = y->k[y->num-1];
        root->k[pos] = y->k[y->num-2];
    }

    for(int i = z->num -1; i > 0; i--) {
        z->k[i] = z->k[i-1];
    }

    if(false == z->is_leaf) {
        for(int i = z->num; i > 0; i--) {
            z->p[i] = z->p[i-1];
        }
        z->p[0] = y->p[y->num];
    } 

    y->num -= 1;
}

void btree_shift_to_left_child(btree_node *root, int pos,
        btree_node *y, btree_node *z)
{
    y->num += 1;

    if(false == z->is_leaf) {
        y->k[y->num-1] = root->k[pos];
        root->k[pos] = z->k[0];
    } else {
        y->k[y->num-1] = z->k[0];
        root->k[pos] = z->k[0];
    }

    for(int j = 1; j < z->num; j++) {
        z->k[j-1] = z->k[j];
    }

    if(false == z->is_leaf) {
        y->p[y->num] = z->p[0];
        for(int j = 1; j <= z->num; j++) {
            z->p[j-1] = z->p[j];
        }
    } 

    z->num -= 1;
}

void btree_inorder_print(btree_node *root)
{
    if(NULL != root) {
        btree_inorder_print(root->p[0]);
        for(int i = 0; i < root->num; i++) {
            printf("%d ", root->k[i]);
            btree_inorder_print(root->p[i+1]);
        }
    }
}

void btree_linear_print(btree_node *root)
{
    if(NULL != root) {
        btree_node *leftmost = root;
        while(false == leftmost->is_leaf) {
            leftmost = leftmost->p[0];
        }

        btree_node *iter = leftmost;
        do {
            for(int i = 0; i < iter->num; i++) {
                printf("%d ", iter->k[i]);
            }
            iter = iter->next;
        } while(iter != leftmost);
        printf("\n");
    }
}

void btree_level_display(btree_node *root)
{

    // just for simplicty, can‘t exceed 200 nodes in the tree
    btree_node *queue[200] = {NULL};
    int front = 0;
    int rear = 0;

    queue[rear++] = root;

    while(front < rear) {
        btree_node *node = queue[front++];

        printf("[");
        for(int i = 0; i < node->num; i++) {
            printf("%d ", node->k[i]);
        }
        printf("]");

        for(int i = 0; i <= node->num; i++) {
            if(NULL != node->p[i]) {
                queue[rear++] = node->p[i];
            }
        }
    }
    printf("\n");
}

int main()
{
    int arr[] = {18, 31, 12, 10, 15, 48, 45, 47, 50, 52, 23, 30, 20};
//    int arr[] = {18, 31, 12, 10};

    btree_node *root = btree_create();

    for(int i = 0; i < sizeof(arr) / sizeof(int); i++) {
        root = btree_insert(root, arr[i]);
        btree_level_display(root);
        btree_linear_print(root);
    }

    //int todel[] = {15, 18, 23, 30, 31, 52, 50};
    int todel[] = {45, 30, 12, 10};
    for(int i = 0; i < sizeof(todel) / sizeof(int); i++) {
        printf("after delete %d\n", todel[i]);
        root = btree_delete(root, todel[i]);
        btree_level_display(root);
        btree_linear_print(root);
    } 

    return 0;
}

时间: 2024-07-28 17:19:16

B树算法与实现 (C语言实现)的相关文章

机器学习算法的R语言实现(二):决策树算法

1.介绍 ?决策树(decision tree)是一种有监督的机器学习算法,是一个分类算法.在给定训练集的条件下,生成一个自顶而下的决策树,树的根为起点,树的叶子为样本的分类,从根到叶子的路径就是一个样本进行分类的过程. ?下图为一个决策树的例子,见http://zh.wikipedia.org/wiki/%E5%86%B3%E7%AD%96%E6%A0%91 ? 可见,决策树上的判断节点是对某一个属性进行判断,生成的路径数量为该属性可能的取值,最终到叶子节点时,就完成一个分类(或预测).决策树

R语言数据挖掘实战系列(1)

R语言数据挖掘实战(1) 一.数据挖掘基础 数据挖掘:从数据中"淘金",从大量数据(包括文本)中挖掘出隐含的.未知的.对决策有潜在价值的关系.模式和趋势,并用这些知识和规则建立用于决策支持的模型,提供预测性决策支持的方法.工具和过程. 数据挖掘的任务 利用分类与预测.聚类分析.关联规则.时序模式.偏差检测.智能推荐等方法,帮助企业提取数据中蕴含的商业价值,提高企业的竞争力. 数据挖掘建模过程 定义挖掘目标,即决定到底想干什么? 数据取样.抽取一个与挖掘目标相关的样本数据子集.抽取数据的

Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 【转】

原文地址:Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938390.html 在构架相关的汇编代码运行完之后,程序跳入了构架无关的内核C语言代码:init/main.c中的start_kernel函数,在这个函数中Linux内核开始真正进入初始化阶段, 下面我就顺这代码逐个函数的解释,但是这里并不会过于深入

如何实现并应用决策树算法?

本文对决策树算法进行简单的总结和梳理,并对著名的决策树算法ID3(Iterative Dichotomiser 迭代二分器)进行实现,实现采用Python语言,一句老梗,“人生苦短,我用Python”,Python确实能够省很多语言方面的事,从而可以让我们专注于问题和解决问题的逻辑. 根据不同的数据,我实现了三个版本的ID3算法,复杂度逐步提升: 1.纯标称值无缺失数据集 2.连续值和标称值混合且无缺失数据集 3.连续值和标称值混合,有缺失数据集 第一个算法参考了<机器学习实战>的大部分代码,

大数据时代的精准数据挖掘——使用R语言

老师简介: Gino老师,即将步入不惑之年,早年获得名校数学与应用数学专业学士和统计学专业硕士,有海外学习和工作的经历,近二十年来一直进行着数据分析的理论和实践,数学.统计和计算机功底强悍. 曾在某一世界500强公司核心部门担任高级主管负责数据建模和分析工作,在实践中攻克统计建模和数据分析难题无数,数据处理与分析科学精准,在实际应用中取得良好的效果. Gino老师担任数据分析培训师多年,探索出一套以实例讲解带动统计原理理解和软件操作熟悉的方法,授课的学生能迅速理解统计原理并使用统计软件独立开展数

R语言数据挖掘实战系列(5)

R语言数据挖掘实战系列(5)--挖掘建模 一.分类与预测 分类和预测是预测问题的两种主要类型,分类主要是预测分类标号(离散属性),而预测主要是建立连续值函数模型,预测给定自变量对应的因变量的值. 1.实现过程 (1)分类 分类是构造一个分类模型,输入样本的属性值,输出对应的类别,将每个样本映射到预先定义好的类别.分类模型建立在已有类标记的数据集上,模型在已有样本上的准确率可以方便地计算,所以分类属于有监督的学习. (2)预测 预测是建立两种或两种以上变量间相互依赖的函数模型,然后进行预测或控制.

Thinking in SQL系列之四:数据挖掘C4.5决策树算法

原创: 牛超   2017-02-11   Mail:[email protected] C4.5是一系列用在机器学习和数据挖掘的分类问题中的算法.它的目标是监督学习:给定一个数据集,其中的每一个元组都能用一组属性值来描述,每一个元组属于一个互斥的类别中的某一类.C4.5的目标是通过学习,积累经验,为后续决策服务. 该算法目前能找到各类版本,C.JAVA.PYTHON.而SQL版本闻所未闻,前篇我有提过,数据处理,SQL为王,如何以SQL的思维来实现C4.5决策树算法是本篇的重点. PS:多年与

R语言︱决策树族——随机森林算法

笔者寄语:有一篇<有监督学习选择深度学习还是随机森林或支持向量机?>(作者Bio:SebastianRaschka)中提到,在日常机器学习工作或学习中,当我们遇到有监督学习相关问题时,不妨考虑下先用简单的假设空间(简单模型集合),例如线性模型逻辑回归.若效果不好,也即并没达到你的预期或评判效果基准时,再进行下换其他更复杂模型来实验. ---------------------------------------------- 一.随机森林理论介绍 1.1 优缺点 优点. (1)不必担心过度拟合

R语言︱XGBoost极端梯度上升以及forecastxgb(预测)+xgboost(回归)双案例解读

R语言︱XGBoost极端梯度上升以及forecastxgb(预测)+xgboost(回归)双案例解读 XGBoost不仅仅可以用来做分类还可以做时间序列方面的预测,而且已经有人做的很好,可以见最后的案例. 应用一:XGBoost用来做预测 -------------------------------------------------- 一.XGBoost来历 xgboost的全称是eXtreme Gradient Boosting.正如其名,它是Gradient Boosting Mach