本文是针对[数据结构基础系列(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-树的基本操作相关推荐

  1. 数据结构树的基本操作_《数据结构》树的基本操作.doc

    <数据结构>树的基本操作 实验四 课程名称:完成日期:姓名:学号:指导教师:实验名称:实验序号:实验成绩:一.实验目的及要求 二.实验环境.实验内容 求出它的深度. .调试过程及实验结果 ...

  2. java树的基本知识_Java数据结构和算法(二)树的基本操作

    Java数据结构和算法(二)树的基本操作 一.树的遍历 二叉树遍历分为:前序遍历.中序遍历.后序遍历.即父结点的访问顺序 1.1 前序遍历 基本思想:先访问根结点,再先序遍历左子树,最后再先序遍历右子 ...

  3. 树形图计算机系统组成,C数据结构的通用树结构和二进制排序树的基本操作

    二叉树: 二叉树是每个节点最多具有两个子树的树结构. 二叉树可以是一个空集:根可以有一个空的左或右子树:或左右子树都为空. 完整的二叉树: 高度为h且由2 {h} – 1个节点组成的二叉树称为完整的二 ...

  4. 数据结构之线段树入门(单点更新区间查询)

    线段树是学习数据结构必须学习的一种数据结构,在ACM,蓝桥等比赛中是经常出现的.利用线段树解题,会使得题目简单易理解.而且线段树是数据结构中比较基础而且用的很多的一种. 线段树定义 线段树是一种二叉搜 ...

  5. 伸展树算法c语言,数据结构之伸展树详解

    1. 概述 二叉查找树(Binary Search Tree,也叫二叉排序树,即Binary Sort Tree)能够支持多种动态集合操作,它可以用来表示有序集合.建立索引等,因而在实际应用中,二叉排 ...

  6. 数据结构实践(有的数据结构课后习题答案),红色是答案

    第1章  绪论 习题 1.简述下列概念:数据.数据元素.数据项.数据对象.数据结构.逻辑结构.存储结构.抽象数据类型. 2.试举一个数据结构的例子,叙述其逻辑结构和存储结构两方面的含义和相互关系. 3 ...

  7. 数据结构与算法——树和二叉树***

    第五章 :树和二叉树 树和图是两种重要的非线性结构.线性结构中结点具有唯一前驱和唯一后继的关系,而非线性结构中结点之间的关系不再具有这种唯一性.其中,树形结构中结点间的关系是前驱唯一而后继不唯一,即元 ...

  8. 《数据结构实践》设计报告---迷宫求解

    <数据结构实践>设计报告-迷宫求解 因为学校要求答辩结课,给了很多题目都不太会,决定把感兴趣的都做一做,在这存档备用. 课程设计题目:迷宫求解 课程设计主要内容和要求: 一.设计目的: 1 ...

  9. 伸展树的基本操作与应用 IOI2004 国家集训队论文 杨思雨

    伸展树的基本操作与应用 安徽省芜湖一中 杨思雨 [关键字] 伸展树 基本操作 应用 [摘要] 本文主要介绍了伸展树的基本操作以及其在解题中的应用.全文可以分为以下四个部分. 第一部分引言,主要说明了二 ...

  10. [数据结构] 常用的树型结构

    这篇文章写得不错原文链接: 数据结构中各种树 - xin Tech - 博客园 数据结构中各种树 阅读目录 1. 二叉树 2. 二叉查找树 3. 平衡二叉树 3.1 平衡查找树之AVL树 3.2 平衡 ...

最新文章

  1. 什么是php递归算法_PHP递归算法(一)
  2. python使用生成器生成浮点数列表、使用生成器生成(正)负的浮点数列表
  3. 阿里云 SSL 证书 总结
  4. ado.net mysql 连接池_ADO.NET中SQL Server数据库连接池
  5. 深入解读Linux内存管理系列(4)——Memblock管理机制
  6. atitit.极光消息推送服务器端开发实现推送  jpush v3. 总结o7p
  7. java 动态修改prooper_java中OOP自己总结的知识点
  8. 如何查看jdkApi在线帮助文档(下载)
  9. 一个div里面包含两个div让两个div垂直居中
  10. 分享这几个好用的文字识别软件,教你快速识别
  11. 软件工程知识点总结——第一、二部分
  12. html5数独游戏设计,数独游戏的前端实现
  13. Linux杀毒软件之ClamAV
  14. Supercell:靠两款手游如何做到30亿美金市值?
  15. 软件测试之App测试-硬件环境测试
  16. 18V降压3.3V,15V降压3.3V的降压IC和LDO芯片方案
  17. 高考计算机会考等级划分标准,高中学业水平考试等级是怎么划分的
  18. 张量积型的Bernstein基函数
  19. 2022-2027年中国自动体外除颤器行业发展监测及投资战略研究报告
  20. Java题解:如何获取某一天的下一天的时间

热门文章

  1. python正则表达式替换excel_在 Excel 中使用正则表达式进行查找与替换
  2. 苹果SSL_goto漏洞简介
  3. 看上去很美--次世代游戏平台XBOX360测评
  4. 4GL是什么?计算机辅助软件工程CASE是什么?
  5. Kali Linux 简介
  6. cogs 1487. 麻球繁衍(概率dp)
  7. 你喜欢的搞笑内容都在这里-----笑口常开
  8. 大数据工程师的海量数据存储学习清单!
  9. Flowerpot(单调队列)
  10. vue-element-admin 的使用记录(三)