[数据结构 C语言] 严蔚敏版 B-树:愿我心里没有B树

B-树的算法实现最难的还是插入操作和删除操作。就连生成B-树也依赖着插入操作。InsertBTree函数比较好的解决方法还是模块化- 将插入之后结点的数目变化分情况讨论,将复杂的逻辑结构拆分成 1、插入结点操作Insert 2、结点分裂操作Split 3、寻找插入相应的位置的操作Search 4、建立新的根节点的操作NewRoot 四个函数,具体应用到各种情况的讨论中。

删除函数需要注意的是指针域的挪动一个都不能马虎。因为连锁反应引起的删除虚拟结点并不是最后一层非终端结点。需要仔仔细细一个数据都不能漏。

此外由于根节点不是叶子结点(NULL)则至少需要两颗子树。不同于其他非终端结点需要(m/2)上限个,因此时时刻刻都需要单独讨论。

 

主要参考:http://www.cnblogs.com/kangjianwei101/p/5221816.html 自己根据理解加上了一些注释,略有微小的改动。

#ifndef B_TREE_H
#define B_TREE_H

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "Base.h"

//B-Tree
//宏定义
#define M 3 //B树的阶
#define MAX_LEVEL 100
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))

//类型定义
typedef ElemType_Search BTElemType;
typedef struct BTNode
{
    int keynum; //结点中的关键字个数
    struct BTNode *parent; //指向双亲结点

    KeyType key[M+1]; //关键字向量,0号单元未用
    struct BTNode *ptr[M+1]; //子树的指针向量
}BTNode; //B树的结点
typedef BTNode *BTree;

//查找结果类型
typedef struct
{
    BTree pt; //指向找到的结点
    int i; //关键字在结点中的序号,即插入位置
    int tag; //1查找成功0查找失败
}Result;

//函数列表
Status CreateBTree (BTree *BT, Table T);

Result SearchBTree (BTree BT, KeyType k);

int Search (BTree p, KeyType k);
//返回k在结点p中的次序,若不存在返回0

Status InsertKey (BTree *BT, KeyType k);
//将关键字k插入树

Status InsertBTree (BTree *BT, KeyType k, BTree q, int i);
//插入算法,在结点*q的key[i]和key[i+1]之间插入关键字k

void Insert (BTree q, KeyType i, KeyType x, BTree ap);
//将x和ap分别插入到q->key[i+1]和q->ptr[i+1]中

void split (BTree q, int s, BTree *ap);
//以s为界,将q指向的结点分裂成q和ap指向的两部分

void NewRoot (BTree *BT, BTree q, int x, BTree ap);
//生成含信息(BT,x,ap)的新的根节点*BT,原BT和ap为子树指针,q初始值为NULL

Status DeleteKey (BTree *BT, KeyType k);
//从B树中删除关键字k

Status DeleteBTree (BTree *BT, BTree q, int i);
//从B树中删除结点q中的第i个关键字

void Delete (BTree *BT, BTree q, int i);
//从B树中删除结点q中的第i个关键字

Status SearchMinKey (BTree BT, Result *R);
//找出BT中最小的关键字

Status FoundParent (BTree q, BTree *p, int *order);
//寻找双亲结点,q为p的第i个孩子

Status LeftMove (BTree old_ptr, int m, BTree new_ptr, int n, int len);
//向左移动关键字和指针

Status RightMove (BTree old_ptr, int m, BTree new_ptr, int n, int len);
//向右移动关键字和指针

void PrintBT_Level (BTree BT);
//层序输出B树

void PrintBT_InOrder (BTree BT);
//中序输出B树
#endif // B_TREE_H
#ifndef B_TREE_C
#define B_TREE_C

#include "B-Tree.h"

//函数列表
Status CreateBTree (BTree *BT, Table T)
{
    int i;
    *BT = NULL;

    if (T.length){
        for (i=1;i<=T.length;i++){
            if (!InsertKey(BT,T.elem[i].key))
                break;
        }
    }

    if (i>T.length)
        return OK;
    else
        return ERROR;
}

Result SearchBTree (BTree BT, KeyType k)
{
    Result R = {NULL,0,0};
    BTree p,q;
    int found,i;

    p = BT;
    q = NULL;
    found = FALSE;
    i=0;

    while (p && !found){
        i = Search(p,k);

        if (i>0 &&p->key[i]==k)
            found  = TRUE;
        else {
            q = p;
            p = p->ptr[i];
        }
    }

    R.i = i;

    if (found){
        R.pt = p;
        R.tag = 1;
    } else {
        R.pt = q;
        R.tag = 0;
    }

    return R;
}

int Search (BTree p, KeyType k)
{
    int i,j;

    for (i=0,j=1;j<=p->keynum;j++){
        if (p->key[j]<=k)
            i = j;
        else
            break;
    }

    return i;
}
//返回k在结点p中的次序,若不存在返回0

Status InsertKey (BTree *BT, KeyType k)
{
    Result R;
    R = SearchBTree(*BT,k);

    if (R.tag==1)
        return ERROR;
    else {
        InsertBTree(BT,k,R.pt,R.i);
    }

    return OK;
}
//将关键字k插入树

Status InsertBTree (BTree *BT, KeyType k, BTree q, int i)
{
    KeyType x = k;
    BTree ap = NULL;
    int finished = FALSE;
    int s;

    while (q && !finished){
        Insert(q,i,x,ap); //将x和ap分别插入到q中

        if (q->keynum<M)
            finished = TRUE;
        else {
            //关键字数目超出限制
            s = ceil((double)M/2); //除根节点之外至少有s棵子树,s-1个关键字

            split(q,s,&ap); //以s为界分q为q和ap
            x = q->key[s];
    
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值