B树
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define T 4
typedef struct B_Tree_Node
{
int n;//指示该结点的关键字个数
int *keys;//该结点关键字数组
int isLeaf;//该结点是否是叶子结点
struct B_Tree_Node **child;//该结点的所有孩子结点
struct B_Tree_Node *p; //该结点的父结点
}B_Tree_Node,*p_B_Tree_Node;
//生成一个新的B树结点
B_Tree_Node *alloact_Node()
{
int i;
B_Tree_Node *newNode=(B_Tree_Node *)malloc(sizeof(B_Tree_Node));
newNode->n=0;
newNode->isLeaf=TRUE;
newNode->keys=(int *) malloc((2*T-1) * sizeof(int));
newNode->child=(p_B_Tree_Node *) malloc((2*T) * sizeof(p_B_Tree_Node));
newNode->p=NULL;
for(i=0;i<2*T;i++)
newNode->child[i]=NULL;
return newNode;
}
//splitNode_p是被分裂结点的父结点,i是索引为i的孩子为满,需要被分裂
//被分裂的结点是满的,那么它的n = 2*T - 1;被分裂为两个T-1个关键字的子结点,同时它的中间元素被提升到其父节点中
void BTree_Child_Split(B_Tree_Node *splitNode_p, int index_child)
{
int i;
B_Tree_Node *newChild = alloact_Node();
newChild->n = T-1;
for(i = 0;i<T-1;i++)
{
newChild->keys[i] = splitNode_p->child[index_child]->keys[T+i];
}
splitNode_p->child[index_child]->n = T-1;
if(splitNode_p->child[index_child]->isLeaf!=TRUE) //如果它的第i个孩子不是叶子结点,则将它的后T个孩子也送给newChild
{
newChild->isLeaf = FALSE;
for(i=0;i<T-1;i++)
newChild->child[i] = splitNode_p->child[i+T];
}
//将newChild 添加为splitNode_p的第i+1个孩子结点,将中间关键字提升到它中
for(i = splitNode_p->n; i>=index_child;i--)
{
splitNode_p->child[i+1] = splitNode_p->child[i];
}
splitNode_p->n++;
splitNode_p->child[index_child+1] = newChild;
for(splitNode_p->n-1; i>=index_child;i--)
{
splitNode_p->keys[i+1] = splitNode_p->keys[i];
}
splitNode_p->keys[index_child] = splitNode_p->child[index_child]->keys[T-1];
}
//在未满的结点插入元素
void BTree_Insert_NonFull(B_Tree_Node *nonfull, int k)
{
int i = nonfull->n - 1;
if(nonfull->isLeaf)
{
while(i>=0&&k<nonfull->keys[i])
{
nonfull->keys[i+1] = nonfull->keys[i];
i--;
}
i = i+1;
(nonfull->n)++;
nonfull->keys[i] = k;
}
else
{
while(i>=0&&k<nonfull->keys[i])
i--;
i = i+1;
if(nonfull->child[i]->n == 2*T-1)
{
BTree_Child_Split(nonfull,i);
if(k>nonfull->keys[i])
i = i+1;
}
BTree_Insert_NonFull(nonfull->child[i],k);
}
}
//在B_Tree中加入新的关键字,主要由BTree_Insert_NonFull来实现,确保每次插入时所访问的结点都是非满结点;
//首先,若根结点为满,则分裂根结点
void BTree_Insert_Node(p_B_Tree_Node *root,int k)
{
B_Tree_Node *p = *root;
if(p->n == 2*T - 1) //如果根结点满
{
B_Tree_Node *newRoot =alloact_Node();
newRoot->child[0] = (*root);
newRoot->isLeaf = FALSE;
*root = newRoot;
BTree_Child_Split(newRoot,0);
BTree_Insert_NonFull(newRoot,k);
}
else
BTree_Insert_NonFull(*root,k);
}
//广度优先搜索遍历输出
void printBFS(B_Tree_Node *t)
{
int i;
if(NULL == t)
return;
//输出当前节点所有关键字
printf(" [");
for(i = 0;i < t->n;++i)
{
printf("%d", t->keys[i]);
if(t->n - 1 != i)
printf(" ");
}
printf("]\n");
//递归输出所有子树
for(i = 0;i <= t->n;++i)
printBFS(t->child[i]);
}
//构造B树
void createBTree(p_B_Tree_Node *root)
{
int i;
int a[] = {12,1,9,2,0,11,7,19,4,15,18,5,14,13,10,16,6,3,8,17};
for(i = 0;i<20;i++)
{
BTree_Insert_Node(root,a[i]);
printf("插入元素%d后\n",a[i]);
printBFS(*root);
}
}
int main()
{
B_Tree_Node *root; //B树根结点
root = alloact_Node();
//构造B树
createBTree(&root);
return 0;
}