#include <stdio.h>
#include <stdlib.h>
#define MIN_DEGREE (3)
#define MAX_KEY (2*MIN_DEGREE -1 )
#define true 1
#define false 0
#define NO_KEY 0
typedef int bool;
//B树节点结构
typedef struct BTreeNode
{
//当前存储的数据个数
int KeyNumber;
//数据数组
int Key[MAX_KEY];
//指针数组
struct BTreeNode *KeyPointer[MAX_KEY + 1];
//是否是叶节点
bool IsLeaf;
}BTreeNode;
//搜索B树返回结果
typedef struct SearchResult
{
//数据所在节点指针
struct BTreeNode *Pointer;
//数据在节点中位置
int KeyPosition;
}SearchResult;
void BTreeSplit(struct BTreeNode *Parent, int ChildPosition, struct BTreeNode *Child );
BTreeNode * BTreeInsertNonfull(struct BTreeNode *Pointer, int data);
void MergeNode(struct BTreeNode *Left, int data, struct BTreeNode *Right);
void DeleteData(struct BTreeNode *Pointer, int Position);
//函数目的:给一个节点分配空间
//接收参数:*Pointer - 节点指针
//返回参数:*Pointer - 节点指针
struct BTreeNode *AllocateNode(struct BTreeNode *Pointer)
{
int i;
//分配内存空间
Pointer = (struct BTreeNode *)malloc(sizeof(struct BTreeNode));
for(i = 0; i <= MAX_KEY; i++)
Pointer->KeyPointer[i] = NULL;
Pointer->IsLeaf = true;
Pointer->KeyNumber = 0;
return Pointer;
}
//函数目的:在B树中递归的搜索给定的数据,如果存在则返回数据所在节点和在节点中的位置,不存在返回NULL
//接收参数: *Root - 树的根节点指针
// data - 要搜索的数据
//返回参数:SearchResult - 数据所在节点和在节点中的位置
struct SearchResult BTreeSearch(struct BTreeNode *Root, int data)
{
int i = 0;
struct SearchResult Result;
//找到节点中数据所在位置
while((i < Root->KeyNumber) && (Root->Key[i] < data))
i++;
//数据找到,返回结果, 由于移除或移动的数据没有被改写,
//Root->KeyPointer[KeyNumber]可能与data相同, 所以要判断i < Root->KeyNumber
if((i < Root->KeyNumber) && (Root->Key[i] == data) )
{
Result.Pointer = Root;
Result.KeyPosition = i;
return Result;
}
//已经搜索到叶节点,数据不存在,返回NULL
if(Root->IsLeaf == true)
{
Result.Pointer = NULL;
Result.KeyPosition = -1;
return Result;
}
//非叶节点,继续搜索子树节点
else
return BTreeSearch(Root->KeyPointer[i], data);
}
//函数目的:向树中插入一个数据
//接收参数:*Root - 树的根节点
// data - 数据
//返回参数:根节点指针
struct BTreeNode *BTreeInsert(struct BTreeNode *Root, int data)
{
struct BTreeNode *NewNode = NULL;
SearchResult seResult;
//BTreeNode *Pointer = NULL;
seResult = BTreeSearch(Root, data);
if(seResult.Pointer != NULL)
{
printf("the data(%d) already in the tree \n", data);
return Root;
}
//检查是否根节点已满,如果已满,分裂并生成新的根节点
if(Root->KeyNumber == MAX_KEY )
{
NewNode = AllocateNode(NewNode);
NewNode->IsLeaf = false;
NewNode->KeyNumber = 0;
NewNode->KeyPointer[0] = Root;
BTreeSplit(NewNode, 0, Root);
BTreeInsertNonfull(NewNode, data);
return NewNode;
}
//还没到最大数据数,直接插入
else
{
BTreeInsertNonfull(Root, data);
return Root;
}
}
//函数目的:分裂存储数达到最大的节点
//接收参数:*Parent - 分裂节点的双亲节点指针
// *Child - 指向分裂节点的指针
// ChildPosition - 分裂节点在双亲节点中的位置
//返回参数:无
void BTreeSplit(struct BTreeNode *Parent, int ChildPosition, struct BTreeNode *Child )
{
int i;
struct BTreeNode *NewNode= NULL;
//为新分裂出的节点分配空间
NewNode = AllocateNode(NewNode);
//与被分裂点同级
NewNode->IsLeaf = Child->IsLeaf;
//设置节点数
NewNode->KeyNumber = MIN_DEGREE - 1;
//复制数据(key)
for(i = 0; i < MIN_DEGREE - 1; i++)
NewNode->Key[i] = Child->Key[i + MIN_DEGREE];
//如果不是叶节点,复制指针
if(false == Child->IsLeaf)
{
for(i = 0; i < MIN_DEGREE; i++)
NewNode->KeyPointer[i] = Child->KeyPointer[i + MIN_DEGREE];
}
Child->KeyNumber = MIN_DEGREE - 1;
//将中间数作为索引插入到父亲节点中
for(i = Parent->KeyNumber; i > ChildPosition; i--)
{
Parent->Key[i] = Parent->Key[i - 1];
Parent->KeyPointer[i + 1] = Parent->KeyPointer[i];
}
Parent->Key[i] = Child->Key[MIN_DEGREE - 1];
Parent->KeyNumber++;
Parent->KeyPointer[i + 1] = NewNode;
}
//函数目的:向非满的节点中插入一个数据
//接收参数:*Pointer - 指向节点的指针
// data - 插入的数据
//返回参数:插入数据的node
BTreeNode * BTreeInsertNonfull(struct BTreeNode *Pointer, int data)
{
int i;
struct BTreeNode *Child= NULL;
i = Pointer->KeyNumber;
//如果是叶节点,直接插入数据
if(Pointer->IsLeaf == true)
{
//移动数据
while((i > 0) && (Pointer->Key[i - 1] > data))
{
Pointer->Key[i] = Pointer->Key[i - 1];
i--;
}
//插入数据
Pointer->Key[i] = data;
Pointer->KeyNumber++;
return Pointer;
}
//不是叶节点,找到数据应插入的子节点并插入
else
{
while((i > 0) && (Pointer->Key[i - 1] > data))
i--;
Child = Pointer->KeyPointer[i];
if(Child->KeyNumber == MAX_KEY)
{
BTreeSplit(Pointer, i, Child);
if(data > Pointer->Key[i])
i++;
}
Child = Pointer->KeyPointer[i];
return BTreeInsertNonfull(Child, data);
}
}
int BTreeDelete(struct BTreeNode **pRoot, int data)
{
struct SearchResult Result;
struct BTreeNode *Pointer= NULL, *TempPointer= NULL;
int i, Temp = 0, j;
BTreeNode* Root= NULL;
Root = *pRoot;
Result = BTreeSearch(Root, data);
Pointer = Result.Pointer;
//数据不在树中,返回失败
if(Pointer == NULL)
{
printf(" the data(%d) is not in the tree\n", data);
return 1;
}
//数据在Root中
if(Pointer == Root)
{
//Root是叶节点 这里是算法导论中的 1)
if(Pointer->IsLeaf == true)
{
DeleteData(Result.Pointer, Result.KeyPosition);
return 0;
}
//Root是中间结点
else
{
//前于数据的子节点中包含多于最小值个数据 算法导论: 2a
if(Root->KeyPointer[Result.KeyPosition]->KeyNumber >= MIN_DEGREE)
{
//找到数据的前驱
TempPointer = Root;
Temp = Result.KeyPosition;
while(TempPointer->KeyPointer[Temp]->IsLeaf == false)
{
TempPointer = TempPointer->KeyPointer[Temp];
Temp = TempPointer->KeyNumber;
}
//记录前驱
TempPointer = TempPointer->KeyPointer[Temp];
Temp = TempPointer->KeyNumber - 1;
Temp = TempPointer->Key[Temp];
//删除前驱
TempPointer = Root->KeyPointer[Result.KeyPosition];
BTreeDelete(&TempPointer, Temp);
//用前驱替换数据
Root->Key[Result.KeyPosition] = Temp;
return 0;
}
//位于数据之后的子节点中包含多于最小值个数据 算法导论 2b
if(Root->KeyPointer[Result.KeyPosition + 1]->KeyNumber >= MIN_DEGREE)
{
//找到数据的后继
TempPointer = Root;
Temp = Result.KeyPosition;
if(TempPointer->KeyPointer[Temp + 1]->IsLeaf == true)
{
TempPointer = TempPointer->KeyPointer[Temp + 1];
}
else
{
TempPointer = TempPointer->KeyPointer[Temp + 1];
while(TempPointer->KeyPointer[0]->IsLeaf == false)
{
TempPointer = TempPointer->KeyPointer[0];
}
//记录后继
TempPointer = TempPointer->KeyPointer[0];
}
Temp = TempPointer->Key[0];
TempPointer = Root->KeyPointer[Result.KeyPosition + 1];
//删除后继
BTreeDelete(&TempPointer, Temp);
//用后继替换数据
Root->Key[Result.KeyPosition] = Temp;
return 0;
}
//子节点都只含有最小值个数据
//合并两个子节点和数据data 算法导论 2c
//i = Root->KeyPointer[Result.KeyPosition + 1]->KeyNumber;
//把右子节点中数据和指针移动到左子节点中
MergeNode(Root->KeyPointer[Result.KeyPosition], Root->Key[Result.KeyPosition],
Root->KeyPointer[Result.KeyPosition + 1]);
TempPointer = Root->KeyPointer[Result.KeyPosition];
//释放右节点内存
free(Root->KeyPointer[Result.KeyPosition + 1]);
//删除数据和指向右子节点的指针
i = Result.KeyPosition;
while(i < Root->KeyNumber - 1)
{
Root->Key[i] = Root->Key[i + 1];
Root->KeyPointer[i + 1] = Root->KeyPointer[i + 2];
i++;
}
Root->KeyNumber--;
//Root可能要被删除, 所以要更新
if(NO_KEY == Root->KeyNumber)
{
free(Root);
//Root = TempPointer;
*pRoot = TempPointer;
}
//删除数据
return BTreeDelete(&TempPointer, data);
}
}
//数据不在Root中
else
{
//找到数据所在子节点的根
i = 0;
while((Root->Key[i] < data) && (i < Root->KeyNumber))
i++;
TempPointer = Root->KeyPointer[i];
Temp = i;
//这个节点中只有最小数的数据 算法导论 3
if(TempPointer->KeyNumber == MIN_DEGREE - 1)
{
//左兄弟节点中有多于最小数的数据 算法导论 3a1
if((i > 0) && (Root->KeyPointer[i - 1]->KeyNumber >= MIN_DEGREE))
{
//下面的操作相当于右旋转
//把父节点中数据降至节点, 放在右子树的最前
//BTreeInsertNonfull(TempPointer, Root->Key[i - 1]);
//先将之节点的数据右移给父节点数据空出位置
for(j = TempPointer->KeyNumber; j > 0; j-- )
{
TempPointer->Key[j] = TempPointer->Key[j - 1];
TempPointer->KeyPointer[j+1]= TempPointer->KeyPointer[j];
}
//最前的指针右移
TempPointer->KeyPointer[1]= TempPointer->KeyPointer[0];
//插入父节点
TempPointer->Key[0] = Root->Key[i - 1];
TempPointer->KeyNumber++;
//把左兄弟节点最右指针移动过来
TempPointer->KeyPointer[0] =
Root->KeyPointer[i - 1]->KeyPointer[Root->KeyPointer[i - 1]->KeyNumber];
//把左节点数据升至父节点
Root->Key[i - 1] = Root->KeyPointer[i - 1]->Key[Root->KeyPointer[i - 1]->KeyNumber - 1];
//delete the last key of left brother
//DeleteData(Root->KeyPointer[i - 1], Root->KeyPointer[i - 1]->KeyNumber - 1);
Root->KeyPointer[i - 1]->KeyNumber--;
return BTreeDelete(&TempPointer, data);
}
//右兄弟节点中有多于最小数的数据 算法导论 3a2
else if((i < Root->KeyNumber) &&
(Root->KeyPointer[i + 1]->KeyNumber >= MIN_DEGREE))
{
//下面的操作相当于左旋转
//把父节点中数据降至节点, 父节点在放在左子树的最后
TempPointer->Key[TempPointer->KeyNumber] = Root->Key[i];
TempPointer->KeyNumber++;
//BTreeInsertNonfull(TempPointer, Root->Key[i]);
//把右兄弟节点最左指针移动过来
TempPointer->KeyPointer[TempPointer->KeyNumber] =
Root->KeyPointer[i + 1]->KeyPointer[0];
//把右节点数据升至父节点
//BTreeInsertNonfull(Root, Root->KeyPointer[i + 1]->Key[0]);
Root->Key[i] = Root->KeyPointer[i + 1]->Key[0];
//
//for(j = 0; ; j > Root->KeyPointer[i + 1]->KeyNumber; j++)
//{
// TempPointer->Key[j] = TempPointer->Key[j-1];
// TempPointer->KeyPointer[j + 1] = TempPointer->KeyPointer[j];
//}
DeleteData(Root->KeyPointer[i + 1], 0);
return BTreeDelete(&TempPointer, data);
}
//兄弟节点都只有最小数据数的数据 算法导论 3b
else
{
//没有左兄弟,与右兄弟合并
if(i == 0)
{
MergeNode(TempPointer, Root->Key[i], Root->KeyPointer[i + 1]);
//释放节点内存
free(Root->KeyPointer[i + 1]);
//BTreeInsertNonfull(TempPointer, Root->Key[i]);
//删除数据和指向节点的指针
while(i < Root->KeyNumber - 1)
{
Root->Key[i] = Root->Key[i + 1];
Root->KeyPointer[i + 1] = Root->KeyPointer[i + 2];
i++;
}
Root->KeyNumber--;
if(NO_KEY == Root->KeyNumber)
{
free(Root);
//Root = TempPointer;
*pRoot = TempPointer;
}
return BTreeDelete(&TempPointer, data);
}
//否则与左兄弟合并
else
{
MergeNode(Root->KeyPointer[i - 1], Root->Key[i - 1], TempPointer);
//释放节点内存
free(TempPointer);
Temp = i - 1;
TempPointer = Root->KeyPointer[i - 1];
//BTreeInsertNonfull(Root->KeyPointer[i - 1], Root->Key[i - 1]);
//删除数据和指向节点的指针
while(i < Root->KeyNumber)
{
Root->Key[i - 1] = Root->Key[i];
Root->KeyPointer[i] = Root->KeyPointer[i + 1];
i++;
}
Root->KeyNumber--;
if(NO_KEY == Root->KeyNumber)
{
free(Root);
//Root = TempPointer;
*pRoot = TempPointer;
}
return BTreeDelete(&TempPointer, data);
}
}
}
return BTreeDelete(&(Root->KeyPointer[Temp]), data);
}
}
//函数目的:合并两个节点和父节点的一个数据
//接收参数:*Left - 左子节点指针
// *Right - 右子节点指针
// data - 父节点的一个数据
//返回参数:无
void MergeNode(struct BTreeNode *Left, int data, struct BTreeNode *Right)
{
int i = 0;
//BTreeNode * pTempNode;
//把数据插入到左子节点中
//pTempNode = BTreeInsertNonfull(Left, data);
Left->Key[Left->KeyNumber] = data;
Left->KeyNumber++;
//把右子节点的数据和指针移动到左子节点中
while(i < Right->KeyNumber)
{
Left->Key[i + Left->KeyNumber] = Right->Key[i];
Left->KeyPointer[i + Left->KeyNumber] = Right->KeyPointer[i];
i++;
}
//The last pointer should be move to left
Left->KeyPointer[i + Left->KeyNumber] = Right->KeyPointer[i];
//改变左节点的数据数
Left->KeyNumber = Left->KeyNumber + Right->KeyNumber;
}
//函数目的:删除节点中的数据
//接收参数:*Pointer - 节点指针
// Position - 删除数据在节点中的位置
//返回参数:无
void DeleteData(struct BTreeNode *Pointer, int Position)
{
int i;
//删除节点并移动数据和指针
for(i = Position; i < Pointer->KeyNumber - 1; i++)
{
Pointer->Key[i] = Pointer->Key[i + 1];
Pointer->KeyPointer[i] = Pointer->KeyPointer[i + 1];
}
Pointer->KeyPointer[Pointer->KeyNumber - 1] = Pointer->KeyPointer[Pointer->KeyNumber];
//减少节点的数据数
Pointer->KeyNumber--;
}
//函数目的:建立一个B树
//接收参数:*Root - 树的根节点指针
//返回参数:*Root - 树的根节点指针
struct BTreeNode *BTreeCreate(struct BTreeNode *Root)
{
Root = AllocateNode(Root);
Root->IsLeaf = true;
Root->KeyNumber = 0;
return Root;
}
//函数目的:广度优先显示树
//接收参数:Root - 树的根节点
//返回参数:无
void BTreeDisplay(struct BTreeNode *Root)
{
int i, QueueNumber = 0;
struct BTreeNode *Queue[100], *CurrentNode;
//加入队列
Queue[QueueNumber] = Root;
QueueNumber++;
while(QueueNumber > 0)
{
//出队
CurrentNode = Queue[0];
QueueNumber--;
i = 0;
while(i < QueueNumber)
{
Queue[i] = Queue[i + 1];
i++;
}
//显示节点
i = 0;
while(i < CurrentNode->KeyNumber)
{
printf("|");
printf("%d", CurrentNode->Key[i]);
i++;
}
if(i != 0)
{
printf("| ");
}
//子节点入队
if(CurrentNode != NULL && CurrentNode->IsLeaf == false)
{
i = 0;
while(i <= CurrentNode->KeyNumber)
{
Queue[QueueNumber] = CurrentNode->KeyPointer[i];
QueueNumber++;
i++;
}
}
}
printf("\n");
}
int main()
{
struct BTreeNode *Root = NULL;
int i = 0, choose = 0, a = 0;
int re = 0;
char c;
Root = BTreeCreate(Root);
//BTreeTestA();
//BTreeTestB();
while(choose != 3)
{
printf("input any character for continue \n");
//for clean the stdin buff
while ((c = getchar()) != '\n' && c != EOF ) ;
printf("function\n");
printf("1.insert\n");
printf("2.delete\n");
printf("3.quit\n");
scanf("%d", &choose);
if(choose == 1)
{
printf("please input insert the data, -1 exit\n");
while(i != -1)
{
//for clean the stdin buff
while ( (c = getchar()) != '\n' && c != EOF ) ;
//fflush(stdin);
re = scanf("%d", &i);
printf("data %d \n", i);
//printf("re %d \n", re);
//scanf("%d", &a);
if(i != -1)
{
Root = BTreeInsert(Root, i);
BTreeDisplay(Root);
}
}
}
else if(choose == 2)
{
printf("input the data need to be deleted -2 exit\n");
while(i != -2)
{
//for clean the stdin buff
while ( (c = getchar()) != '\n' && c != EOF ) ;
scanf("%d", &i);
printf("data %d \n", i);
if(i != -2)
{
i = BTreeDelete(&Root, i);
BTreeDisplay(Root);
}
}
}
}
return 0;
}
B树的实现
最新推荐文章于 2023-10-11 18:21:38 发布