数据结构实践——B-树的基本操作
本文是针对[数据结构基础系列(8):查找]的实践。
【项目 - B-树的基本操作】
实现B-树的基本操作。基于序列{4, 9, 0, 1, 8, 6, 3, 5, 2, 7}完成测试。
(1)创建对应的3阶B-树b,用括号法输出b树。
(2)从b中分别删除关键字为8和1的节点,用括号法输出删除节点后的b树。
[参考解答]
#include <stdio.h>
#include <malloc.h>
#define MAXM 10 //定义B-树的最大的阶数
typedef int KeyType; //KeyType为关键字类型
typedef struct node //B-树结点类型定义
{int keynum; //结点当前拥有的关键字的个数KeyType key[MAXM]; //key[1..keynum]存放关键字,key[0]不用struct node *parent; //双亲结点指针struct node *ptr[MAXM]; //孩子结点指针数组ptr[0..keynum]
} BTNode;
typedef struct //B-树的查找结果类型
{BTNode *pt; //指向找到的结点int i; //1..m,在结点中的关键字序号int tag; //1:查找成功,O:查找失败
} Result;
int m; //m阶B-树,为全局变量
int Max; //m阶B-树中每个结点的至多关键字个数,Max=m-1
int Min; //m阶B-树中非叶子结点的至少关键字个数,Min=(m-1)/2
int Search(BTNode *p,KeyType k)
{//在p->key[1..keynum]中查找i,使得p->key[i]<=k<p->key[i+1]int i=0;for(i=0; i<p->keynum && p->key[i+1]<=k; i++);return i;
}
Result SearchBTree(BTNode *t,KeyType k)
{/*在m阶t树t上查找关键字k,返回结果(pt,i,tag)。若查找成功,则特征值tag=1,指针pt所指结点中第i个关键字等于k;否则特征值tag=0,等于k的关键字应插入在指针Pt所指结点中第i和第i+1个关键字之间*/BTNode *p=t,*q=NULL; //初始化,p指向待查结点,q指向p的双亲int found=0,i=0;Result r;while (p!=NULL && found==0){i=Search(p,k); //在p->key[1..keynum]中查找i,使得p->key[i]<=k<p->key[i+1]if (i>0 && p->key[i]==k) //找到待查关键字found=1;else{q=p;p=p->ptr[i];}}r.i=i;if (found==1) //查找成功{r.pt=p;r.tag=1;}else //查找不成功,返回K的插入位置信息{r.pt=q;r.tag=0;}return r; //返回k的位置(或插入位置)
}
void Insert(BTNode *&q,int i,KeyType x,BTNode *ap)
{//将x和ap分别插入到q->key[i+1]和q->ptr[i+1]中int j;for(j=q->keynum; j>i; j--) //空出一个位置{q->key[j+1]=q->key[j];q->ptr[j+1]=q->ptr[j];}q->key[i+1]=x;q->ptr[i+1]=ap;if (ap!=NULL) ap->parent=q;q->keynum++;
}
void Split(BTNode *&q,BTNode *&ap)
{//将结点q分裂成两个结点,前一半保留,后一半移入新生结点apint i,s=(m+1)/2;ap=(BTNode *)malloc(sizeof(BTNode)); //生成新结点*apap->ptr[0]=q->ptr[s]; //后一半移入apfor (i=s+1; i<=m; i++){ap->key[i-s]=q->key[i];ap->ptr[i-s]=q->ptr[i];if (ap->ptr[i-s]!=NULL)ap->ptr[i-s]->parent=ap;}ap->keynum=q->keynum-s;ap->parent=q->parent;for (i=0; i<=q->keynum-s; i++) //修改指向双亲结点的指针if (ap->ptr[i]!=NULL) ap->ptr[i]->parent = ap;q->keynum=s-1; //q的前一半保留,修改keynum
}
void NewRoot(BTNode *&t,BTNode *p,KeyType x,BTNode *ap)
{//生成含信息(T,x,ap)的新的根结点*t,原t和ap为子树指针t=(BTNode *)malloc(sizeof(BTNode));t->keynum=1;t->ptr[0]=p;t->ptr[1]=ap;t->key[1]=x;if (p!=NULL) p->parent=t;if (ap!=NULL) ap->parent=t;t->parent=NULL;
}
void InsertBTree(BTNode *&t, KeyType k, BTNode *q, int i)
{/*在m阶t树t上结点*q的key[i]与key[i+1]之间插入关键字k。若引起结点过大,则沿双亲链进行必要的结点分裂调整,使t仍是m阶t树。*/BTNode *ap;int finished,needNewRoot,s;KeyType x;if (q==NULL) //t是空树(参数q初值为NULL)NewRoot(t,NULL,k,NULL); //生成仅含关键字k的根结点*telse{x=k;ap=NULL;finished=needNewRoot=0;while (needNewRoot==0 && finished==0){Insert(q,i,x,ap); //将x和ap分别插入到q->key[i+1]和q->ptr[i+1]if (q->keynum<=Max) finished=1; //插入完成else{//分裂结点*q,将q->key[s+1..m],q->ptr[s..m]和q->recptr[s+1..m]移入新结点*aps=(m+1)/2;Split(q,ap);x=q->key[s];if (q->parent) //在双亲结点*q中查找x的插入位置{q=q->parent;i=Search(q, x);}else needNewRoot=1;}}if (needNewRoot==1) //根结点已分裂为结点*q和*apNewRoot(t,q,x,ap); //生成新根结点*t,q和ap为子树指针}
}
void DispBTree(BTNode *t) //以括号表示法输出B-树
{int i;if (t!=NULL){printf("["); //输出当前结点关键字for (i=1; i<t->keynum; i++)printf("%d ",t->key[i]);printf("%d",t->key[i]);printf("]");if (t->keynum>0){if (t->ptr[0]!=0) printf("("); //至少有一个子树时输出"("号for (i=0; i<t->keynum; i++) //对每个子树进行递归调用{DispBTree(t->ptr[i]);if (t->ptr[i+1]!=NULL) printf(",");}DispBTree(t->ptr[t->keynum]);if (t->ptr[0]!=0) printf(")"); //至少有一个子树时输出")"号}}
}
void Remove(BTNode *p,int i)
//从*p结点删除key[i]和它的孩子指针ptr[i]
{int j;for (j=i+1; j<=p->keynum; j++) //前移删除key[i]和ptr[i]{p->key[j-1]=p->key[j];p->ptr[j-1]=p->ptr[j];}p->keynum--;
}
void Successor(BTNode *p,int i)
//查找被删关键字p->key[i](在非叶子结点中)的替代叶子结点
{BTNode *q;for (q=p->ptr[i]; q->ptr[0]!=NULL; q=q->ptr[0]);p->key[i]=q->key[1]; //复制关键字值
}
void MoveRight(BTNode *p,int i)
//把一个关键字移动到右兄弟中
{int c;BTNode *t=p->ptr[i];for (c=t->keynum; c>0; c--) //将右兄弟中所有关键字移动一位{t->key[c+1]=t->key[c];t->ptr[c+1]=t->ptr[c];}t->ptr[1]=t->ptr[0]; //从双亲结点移动关键字到右兄弟中t->keynum++;t->key[1]=p->key[i];t=p->ptr[i-1]; //将左兄弟中最后一个关键字移动到双亲结点中p->key[i]=t->key[t->keynum];p->ptr[i]->ptr[0]=t->ptr[t->keynum];t->keynum--;
}
void MoveLeft(BTNode *p,int i)
//把一个关键字移动到左兄弟中
{int c;BTNode *t;t=p->ptr[i-1]; //把双亲结点中的关键字移动到左兄弟中t->keynum++;t->key[t->keynum]=p->key[i];t->ptr[t->keynum]=p->ptr[i]->ptr[0];t=p->ptr[i]; //把右兄弟中的关键字移动到双亲兄弟中p->key[i]=t->key[1];p->ptr[0]=t->ptr[1];t->keynum--;for (c=1; c<=t->keynum; c++) //将右兄弟中所有关键字移动一位{t->key[c]=t->key[c+1];t->ptr[c]=t->ptr[c+1];}
}
void Combine(BTNode *p,int i)
//将三个结点合并到一个结点中
{int c;BTNode *q=p->ptr[i]; //指向右结点,它将被置空和删除BTNode *l=p->ptr[i-1];l->keynum++; //l指向左结点l->key[l->keynum]=p->key[i];l->ptr[l->keynum]=q->ptr[0];for (c=1; c<=q->keynum; c++) //插入右结点中的所有关键字{l->keynum++;l->key[l->keynum]=q->key[c];l->ptr[l->keynum]=q->ptr[c];}for (c=i; c<p->keynum; c++) //删除父结点所有的关键字{p->key[c]=p->key[c+1];p->ptr[c]=p->ptr[c+1];}p->keynum--;free(q); //释放空右结点的空间
}
void Restore(BTNode *p,int i)
//关键字删除后,调整B-树,找到一个关键字将其插入到p->ptr[i]中
{if (i==0) //为最左边关键字的情况if (p->ptr[1]->keynum>Min)MoveLeft(p,1);elseCombine(p,1);else if (i==p->keynum) //为最右边关键字的情况if (p->ptr[i-1]->keynum>Min)MoveRight(p,i);elseCombine(p,i);else if (p->ptr[i-1]->keynum>Min) //为其他情况MoveRight(p,i);else if (p->ptr[i+1]->keynum>Min)MoveLeft(p,i+1);elseCombine(p,i);
}
int SearchNode(KeyType k,BTNode *p,int &i)
//在结点p中找关键字为k的位置i,成功时返回1,否则返回0
{if (k<p->key[1]) //k小于*p结点的最小关键字时返回0{i=0;return 0;}else //在*p结点中查找{i=p->keynum;while (k<p->key[i] && i>1)i--;return(k==p->key[i]);}
}
int RecDelete(KeyType k,BTNode *p)
//查找并删除关键字k
{int i;int found;if (p==NULL)return 0;else{if ((found=SearchNode(k,p,i))==1) //查找关键字k{if (p->ptr[i-1]!=NULL) //若为非叶子结点{Successor(p,i); //由其后继代替它RecDelete(p->key[i],p->ptr[i]); //p->key[i]在叶子结点中}elseRemove(p,i); //从*p结点中位置i处删除关键字}elsefound=RecDelete(k,p->ptr[i]); //沿孩子结点递归查找并删除关键字kif (p->ptr[i]!=NULL)if (p->ptr[i]->keynum<Min) //删除后关键字个数小于MINRestore(p,i);return found;}
}
void DeleteBTree(KeyType k,BTNode *&root)
//从B-树root中删除关键字k,若在一个结点中删除指定的关键字,不再有其他关键字,则删除该结点
{BTNode *p; //用于释放一个空的rootif (RecDelete(k,root)==0)printf(" 关键字%d不在B-树中\n",k);else if (root->keynum==0){p=root;root=root->ptr[0];free(p);}
}
int main()
{BTNode *t=NULL;Result s;int j,n=10;KeyType a[]= {4,9,0,1,8,6,3,5,2,7},k;m=3; //3阶B-树Max=m-1;Min=(m-1)/2;printf("创建一棵%d阶B-树:\n",m);for (j=0; j<n; j++) //创建一棵3阶B-树t{s=SearchBTree(t,a[j]);if (s.tag==0)InsertBTree(t,a[j],s.pt,s.i);printf(" 第%d步,插入%d: ",j+1,a[j]);DispBTree(t);printf("\n");}printf(" 结果B-树: ");DispBTree(t);printf("\n");printf("删除操作:\n");k=8;DeleteBTree(k,t);printf(" 删除%d: ",k);printf("B-树: ");DispBTree(t);printf("\n");k=1;DeleteBTree(k,t);printf(" 删除%d: ",k);printf("B-树: ");DispBTree(t);printf("\n");return 0;
}
数据结构实践——B-树的基本操作相关推荐
- 数据结构树的基本操作_《数据结构》树的基本操作.doc
<数据结构>树的基本操作 实验四 课程名称:完成日期:姓名:学号:指导教师:实验名称:实验序号:实验成绩:一.实验目的及要求 二.实验环境.实验内容 求出它的深度. .调试过程及实验结果 ...
- java树的基本知识_Java数据结构和算法(二)树的基本操作
Java数据结构和算法(二)树的基本操作 一.树的遍历 二叉树遍历分为:前序遍历.中序遍历.后序遍历.即父结点的访问顺序 1.1 前序遍历 基本思想:先访问根结点,再先序遍历左子树,最后再先序遍历右子 ...
- 树形图计算机系统组成,C数据结构的通用树结构和二进制排序树的基本操作
二叉树: 二叉树是每个节点最多具有两个子树的树结构. 二叉树可以是一个空集:根可以有一个空的左或右子树:或左右子树都为空. 完整的二叉树: 高度为h且由2 {h} – 1个节点组成的二叉树称为完整的二 ...
- 数据结构之线段树入门(单点更新区间查询)
线段树是学习数据结构必须学习的一种数据结构,在ACM,蓝桥等比赛中是经常出现的.利用线段树解题,会使得题目简单易理解.而且线段树是数据结构中比较基础而且用的很多的一种. 线段树定义 线段树是一种二叉搜 ...
- 伸展树算法c语言,数据结构之伸展树详解
1. 概述 二叉查找树(Binary Search Tree,也叫二叉排序树,即Binary Sort Tree)能够支持多种动态集合操作,它可以用来表示有序集合.建立索引等,因而在实际应用中,二叉排 ...
- 数据结构实践(有的数据结构课后习题答案),红色是答案
第1章 绪论 习题 1.简述下列概念:数据.数据元素.数据项.数据对象.数据结构.逻辑结构.存储结构.抽象数据类型. 2.试举一个数据结构的例子,叙述其逻辑结构和存储结构两方面的含义和相互关系. 3 ...
- 数据结构与算法——树和二叉树***
第五章 :树和二叉树 树和图是两种重要的非线性结构.线性结构中结点具有唯一前驱和唯一后继的关系,而非线性结构中结点之间的关系不再具有这种唯一性.其中,树形结构中结点间的关系是前驱唯一而后继不唯一,即元 ...
- 《数据结构实践》设计报告---迷宫求解
<数据结构实践>设计报告-迷宫求解 因为学校要求答辩结课,给了很多题目都不太会,决定把感兴趣的都做一做,在这存档备用. 课程设计题目:迷宫求解 课程设计主要内容和要求: 一.设计目的: 1 ...
- 伸展树的基本操作与应用 IOI2004 国家集训队论文 杨思雨
伸展树的基本操作与应用 安徽省芜湖一中 杨思雨 [关键字] 伸展树 基本操作 应用 [摘要] 本文主要介绍了伸展树的基本操作以及其在解题中的应用.全文可以分为以下四个部分. 第一部分引言,主要说明了二 ...
- [数据结构] 常用的树型结构
这篇文章写得不错原文链接: 数据结构中各种树 - xin Tech - 博客园 数据结构中各种树 阅读目录 1. 二叉树 2. 二叉查找树 3. 平衡二叉树 3.1 平衡查找树之AVL树 3.2 平衡 ...
最新文章
- 什么是php递归算法_PHP递归算法(一)
- python使用生成器生成浮点数列表、使用生成器生成(正)负的浮点数列表
- 阿里云 SSL 证书 总结
- ado.net mysql 连接池_ADO.NET中SQL Server数据库连接池
- 深入解读Linux内存管理系列(4)——Memblock管理机制
- atitit.极光消息推送服务器端开发实现推送 jpush v3. 总结o7p
- java 动态修改prooper_java中OOP自己总结的知识点
- 如何查看jdkApi在线帮助文档(下载)
- 一个div里面包含两个div让两个div垂直居中
- 分享这几个好用的文字识别软件,教你快速识别
- 软件工程知识点总结——第一、二部分
- html5数独游戏设计,数独游戏的前端实现
- Linux杀毒软件之ClamAV
- Supercell:靠两款手游如何做到30亿美金市值?
- 软件测试之App测试-硬件环境测试
- 18V降压3.3V,15V降压3.3V的降压IC和LDO芯片方案
- 高考计算机会考等级划分标准,高中学业水平考试等级是怎么划分的
- 张量积型的Bernstein基函数
- 2022-2027年中国自动体外除颤器行业发展监测及投资战略研究报告
- Java题解:如何获取某一天的下一天的时间