第十五周项目3-B-树的基本操作

问题及代码:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. *    
  2. * Copyright (c)2016,烟台大学计算机与控制工程学院    
  3. * All rights reserved.    
  4. * 文件名称:ccc.cpp    
  5. * 作    者:陈晓琳  
  6. * 完成日期:2016年12月16日    
  7. * 版 本 号:v1.0    
  8.     
  9. * 问题描述:    
  10.         实现B-树的基本操作。基于序列{4, 9, 0, 1, 8, 6, 3, 5, 2, 7}完成测试。     
  11.             
  12.         (1)创建对应的3阶B-树b,用括号法输出b树。     
  13.         (2)从b中分别删除关键字为8和1的节点,用括号法输出删除节点后的b树。    
  14.     
  15. * 输入描述:无    
  16. * 程序输出:测试数据    
  17. */      

代码:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>      
  2. #include <malloc.h>      
  3. #define MAXM 10                     //定义B-树的最大的阶数      
  4. typedef int KeyType;                //KeyType为关键字类型      
  5. typedef struct node                 //B-树结点类型定义      
  6. {      
  7.     int keynum;                     //结点当前拥有的关键字的个数      
  8.     KeyType key[MAXM];              //key[1..keynum]存放关键字,key[0]不用      
  9.     struct node *parent;            //双亲结点指针      
  10.     struct node *ptr[MAXM];         //孩子结点指针数组ptr[0..keynum]      
  11. } BTNode;      
  12. typedef struct                      //B-树的查找结果类型      
  13. {      
  14.     BTNode *pt;                     //指向找到的结点      
  15.     int i;                          //1..m,在结点中的关键字序号      
  16.     int tag;                        //1:查找成功,O:查找失败      
  17. }  Result;      
  18. int m;                              //m阶B-树,为全局变量      
  19. int Max;                            //m阶B-树中每个结点的至多关键字个数,Max=m-1      
  20. int Min;                            //m阶B-树中非叶子结点的至少关键字个数,Min=(m-1)/2      
  21. int Search(BTNode *p,KeyType k)      
  22. {      
  23.     //在p->key[1..keynum]中查找i,使得p->key[i]<=k<p->key[i+1]      
  24.     int i=0;      
  25.     for(i=0; i<p->keynum && p->key[i+1]<=k; i++);      
  26.     return i;      
  27. }      
  28. Result SearchBTree(BTNode *t,KeyType k)      
  29. {      
  30.     /*在m阶t树t上查找关键字k,返回结果(pt,i,tag)。若查找成功,则特征值   
  31.      tag=1,指针pt所指结点中第i个关键字等于k;否则特征值tag=0,等于k的   
  32.      关键字应插入在指针Pt所指结点中第i和第i+1个关键字之间*/      
  33.     BTNode *p=t,*q=NULL; //初始化,p指向待查结点,q指向p的双亲      
  34.     int found=0,i=0;      
  35.     Result r;      
  36.     while (p!=NULL && found==0)      
  37.     {      
  38.         i=Search(p,k);              //在p->key[1..keynum]中查找i,使得p->key[i]<=k<p->key[i+1]      
  39.         if (i>0 && p->key[i]==k)    //找到待查关键字      
  40.             found=1;      
  41.         else      
  42.         {      
  43.             q=p;      
  44.             p=p->ptr[i];      
  45.         }      
  46.     }      
  47.     r.i=i;      
  48.     if (found==1)                   //查找成功      
  49.     {      
  50.         r.pt=p;      
  51.         r.tag=1;      
  52.     }      
  53.     else                            //查找不成功,返回K的插入位置信息      
  54.     {      
  55.         r.pt=q;      
  56.         r.tag=0;      
  57.     }      
  58.     return r;                       //返回k的位置(或插入位置)      
  59. }      
  60. void Insert(BTNode *&q,int i,KeyType x,BTNode *ap)      
  61. {      
  62.     //将x和ap分别插入到q->key[i+1]和q->ptr[i+1]中      
  63.     int j;      
  64.     for(j=q->keynum; j>i; j--)  //空出一个位置      
  65.     {      
  66.         q->key[j+1]=q->key[j];      
  67.         q->ptr[j+1]=q->ptr[j];      
  68.     }      
  69.     q->key[i+1]=x;      
  70.     q->ptr[i+1]=ap;      
  71.     if (ap!=NULL) ap->parent=q;      
  72.     q->keynum++;      
  73. }      
  74. void Split(BTNode *&q,BTNode *&ap)      
  75. {      
  76.     //将结点q分裂成两个结点,前一半保留,后一半移入新生结点ap      
  77.     int i,s=(m+1)/2;      
  78.     ap=(BTNode *)malloc(sizeof(BTNode));    //生成新结点*ap      
  79.     ap->ptr[0]=q->ptr[s];                   //后一半移入ap      
  80.     for (i=s+1; i<=m; i++)      
  81.     {      
  82.         ap->key[i-s]=q->key[i];      
  83.         ap->ptr[i-s]=q->ptr[i];      
  84.         if (ap->ptr[i-s]!=NULL)      
  85.             ap->ptr[i-s]->parent=ap;      
  86.     }      
  87.     ap->keynum=q->keynum-s;      
  88.     ap->parent=q->parent;      
  89.     for (i=0; i<=q->keynum-s; i++) //修改指向双亲结点的指针      
  90.         if (ap->ptr[i]!=NULL) ap->ptr[i]->parent = ap;      
  91.     q->keynum=s-1;                      //q的前一半保留,修改keynum      
  92. }      
  93. void NewRoot(BTNode *&t,BTNode *p,KeyType x,BTNode *ap)      
  94. {      
  95.     //生成含信息(T,x,ap)的新的根结点*t,原t和ap为子树指针      
  96.     t=(BTNode *)malloc(sizeof(BTNode));      
  97.     t->keynum=1;      
  98.     t->ptr[0]=p;      
  99.     t->ptr[1]=ap;      
  100.     t->key[1]=x;      
  101.     if (p!=NULL) p->parent=t;      
  102.     if (ap!=NULL) ap->parent=t;      
  103.     t->parent=NULL;      
  104. }      
  105. void InsertBTree(BTNode *&t, KeyType k, BTNode *q, int i)      
  106. {      
  107.     /*在m阶t树t上结点*q的key[i]与key[i+1]之间插入关键字k。若引起   
  108.      结点过大,则沿双亲链进行必要的结点分裂调整,使t仍是m阶t树。*/      
  109.     BTNode *ap;      
  110.     int finished,needNewRoot,s;      
  111.     KeyType x;      
  112.     if (q==NULL)                        //t是空树(参数q初值为NULL)      
  113.         NewRoot(t,NULL,k,NULL);         //生成仅含关键字k的根结点*t      
  114.     else      
  115.     {      
  116.         x=k;      
  117.         ap=NULL;      
  118.         finished=needNewRoot=0;      
  119.         while (needNewRoot==0 && finished==0)      
  120.         {      
  121.             Insert(q,i,x,ap);               //将x和ap分别插入到q->key[i+1]和q->ptr[i+1]      
  122.             if (q->keynum<=Max) finished=1; //插入完成      
  123.             else      
  124.             {      
  125.                 //分裂结点*q,将q->key[s+1..m],q->ptr[s..m]和q->recptr[s+1..m]移入新结点*ap      
  126.                 s=(m+1)/2;      
  127.                 Split(q,ap);      
  128.                 x=q->key[s];      
  129.                 if (q->parent)              //在双亲结点*q中查找x的插入位置      
  130.                 {      
  131.                     q=q->parent;      
  132.                     i=Search(q, x);      
  133.                 }      
  134.                 else needNewRoot=1;      
  135.             }      
  136.         }      
  137.         if (needNewRoot==1)                 //根结点已分裂为结点*q和*ap      
  138.             NewRoot(t,q,x,ap);              //生成新根结点*t,q和ap为子树指针      
  139.     }      
  140. }      
  141. void DispBTree(BTNode *t)   //以括号表示法输出B-树      
  142. {      
  143.     int i;      
  144.     if (t!=NULL)      
  145.     {      
  146.         printf("[");            //输出当前结点关键字      
  147.         for (i=1; i<t->keynum; i++)      
  148.             printf("%d ",t->key[i]);      
  149.         printf("%d",t->key[i]);      
  150.         printf("]");      
  151.         if (t->keynum>0)      
  152.         {      
  153.             if (t->ptr[0]!=0) printf("(");  //至少有一个子树时输出"("号      
  154.             for (i=0; i<t->keynum; i++)     //对每个子树进行递归调用      
  155.             {      
  156.                 DispBTree(t->ptr[i]);      
  157.                 if (t->ptr[i+1]!=NULL) printf(",");      
  158.             }      
  159.             DispBTree(t->ptr[t->keynum]);      
  160.             if (t->ptr[0]!=0) printf(")");  //至少有一个子树时输出")"号      
  161.         }      
  162.     }      
  163. }      
  164. void Remove(BTNode *p,int i)      
  165. //从*p结点删除key[i]和它的孩子指针ptr[i]      
  166. {      
  167.     int j;      
  168.     for (j=i+1; j<=p->keynum; j++)      //前移删除key[i]和ptr[i]      
  169.     {      
  170.         p->key[j-1]=p->key[j];      
  171.         p->ptr[j-1]=p->ptr[j];      
  172.     }      
  173.     p->keynum--;      
  174. }      
  175. void Successor(BTNode *p,int i)      
  176. //查找被删关键字p->key[i](在非叶子结点中)的替代叶子结点      
  177. {      
  178.     BTNode *q;      
  179.     for (q=p->ptr[i]; q->ptr[0]!=NULL; q=q->ptr[0]);      
  180.     p->key[i]=q->key[1];    //复制关键字值      
  181. }      
  182. void MoveRight(BTNode *p,int i)      
  183. //把一个关键字移动到右兄弟中      
  184. {      
  185.     int c;      
  186.     BTNode *t=p->ptr[i];      
  187.     for (c=t->keynum; c>0; c--) //将右兄弟中所有关键字移动一位      
  188.     {      
  189.         t->key[c+1]=t->key[c];      
  190.         t->ptr[c+1]=t->ptr[c];      
  191.     }      
  192.     t->ptr[1]=t->ptr[0];        //从双亲结点移动关键字到右兄弟中      
  193.     t->keynum++;      
  194.     t->key[1]=p->key[i];      
  195.     t=p->ptr[i-1];              //将左兄弟中最后一个关键字移动到双亲结点中      
  196.     p->key[i]=t->key[t->keynum];      
  197.     p->ptr[i]->ptr[0]=t->ptr[t->keynum];      
  198.     t->keynum--;      
  199. }      
  200. void MoveLeft(BTNode *p,int i)      
  201. //把一个关键字移动到左兄弟中      
  202. {      
  203.     int c;      
  204.     BTNode *t;      
  205.     t=p->ptr[i-1];              //把双亲结点中的关键字移动到左兄弟中      
  206.     t->keynum++;      
  207.     t->key[t->keynum]=p->key[i];      
  208.     t->ptr[t->keynum]=p->ptr[i]->ptr[0];      
  209.       
  210.     t=p->ptr[i];                //把右兄弟中的关键字移动到双亲兄弟中      
  211.     p->key[i]=t->key[1];      
  212.     p->ptr[0]=t->ptr[1];      
  213.     t->keynum--;      
  214.     for (c=1; c<=t->keynum; c++)    //将右兄弟中所有关键字移动一位      
  215.     {      
  216.         t->key[c]=t->key[c+1];      
  217.         t->ptr[c]=t->ptr[c+1];      
  218.     }      
  219. }      
  220. void Combine(BTNode *p,int i)      
  221. //将三个结点合并到一个结点中      
  222. {      
  223.     int c;      
  224.     BTNode *q=p->ptr[i];            //指向右结点,它将被置空和删除      
  225.     BTNode *l=p->ptr[i-1];      
  226.     l->keynum++;                    //l指向左结点      
  227.     l->key[l->keynum]=p->key[i];      
  228.     l->ptr[l->keynum]=q->ptr[0];      
  229.     for (c=1; c<=q->keynum; c++)        //插入右结点中的所有关键字      
  230.     {      
  231.         l->keynum++;      
  232.         l->key[l->keynum]=q->key[c];      
  233.         l->ptr[l->keynum]=q->ptr[c];      
  234.     }      
  235.     for (c=i; c<p->keynum; c++)     //删除父结点所有的关键字      
  236.     {      
  237.         p->key[c]=p->key[c+1];      
  238.         p->ptr[c]=p->ptr[c+1];      
  239.     }      
  240.     p->keynum--;      
  241.     free(q);                        //释放空右结点的空间      
  242. }      
  243. void Restore(BTNode *p,int i)      
  244. //关键字删除后,调整B-树,找到一个关键字将其插入到p->ptr[i]中      
  245. {      
  246.     if (i==0)                           //为最左边关键字的情况      
  247.         if (p->ptr[1]->keynum>Min)      
  248.             MoveLeft(p,1);      
  249.         else      
  250.             Combine(p,1);      
  251.     else if (i==p->keynum)              //为最右边关键字的情况      
  252.         if (p->ptr[i-1]->keynum>Min)      
  253.             MoveRight(p,i);      
  254.         else      
  255.             Combine(p,i);      
  256.     else if (p->ptr[i-1]->keynum>Min)   //为其他情况      
  257.         MoveRight(p,i);      
  258.     else if (p->ptr[i+1]->keynum>Min)      
  259.         MoveLeft(p,i+1);      
  260.     else      
  261.         Combine(p,i);      
  262. }      
  263. int SearchNode(KeyType k,BTNode *p,int &i)      
  264. //在结点p中找关键字为k的位置i,成功时返回1,否则返回0      
  265. {      
  266.     if (k<p->key[1])    //k小于*p结点的最小关键字时返回0      
  267.     {      
  268.         i=0;      
  269.         return 0;      
  270.     }      
  271.     else                //在*p结点中查找      
  272.     {      
  273.         i=p->keynum;      
  274.         while (k<p->key[i] && i>1)      
  275.             i--;      
  276.         return(k==p->key[i]);      
  277.     }      
  278. }      
  279. int RecDelete(KeyType k,BTNode *p)      
  280. //查找并删除关键字k      
  281. {      
  282.     int i;      
  283.     int found;      
  284.     if (p==NULL)      
  285.         return 0;      
  286.     else      
  287.     {      
  288.         if ((found=SearchNode(k,p,i))==1)       //查找关键字k      
  289.         {      
  290.             if (p->ptr[i-1]!=NULL)              //若为非叶子结点      
  291.             {      
  292.                 Successor(p,i);                 //由其后继代替它      
  293.                 RecDelete(p->key[i],p->ptr[i]); //p->key[i]在叶子结点中      
  294.             }      
  295.             else      
  296.                 Remove(p,i);                    //从*p结点中位置i处删除关键字      
  297.         }      
  298.         else      
  299.             found=RecDelete(k,p->ptr[i]);       //沿孩子结点递归查找并删除关键字k      
  300.         if (p->ptr[i]!=NULL)      
  301.             if (p->ptr[i]->keynum<Min)          //删除后关键字个数小于MIN      
  302.                 Restore(p,i);      
  303.         return found;      
  304.     }      
  305. }      
  306. void DeleteBTree(KeyType k,BTNode *&root)      
  307. //从B-树root中删除关键字k,若在一个结点中删除指定的关键字,不再有其他关键字,则删除该结点      
  308. {      
  309.     BTNode *p;              //用于释放一个空的root      
  310.     if (RecDelete(k,root)==0)      
  311.         printf("   关键字%d不在B-树中\n",k);      
  312.     else if (root->keynum==0)      
  313.     {      
  314.         p=root;      
  315.         root=root->ptr[0];      
  316.         free(p);      
  317.     }      
  318. }      
  319. int main()      
  320. {      
  321.     BTNode *t=NULL;      
  322.     Result s;      
  323.     int j,n=10;      
  324.     KeyType a[]= {4,9,0,1,8,6,3,5,2,7},k;      
  325.     m=3;                                //3阶B-树      
  326.     Max=m-1;      
  327.     Min=(m-1)/2;      
  328.     printf("创建一棵%d阶B-树:\n",m);      
  329.     for (j=0; j<n; j++)                 //创建一棵3阶B-树t      
  330.     {      
  331.         s=SearchBTree(t,a[j]);      
  332.         if (s.tag==0)      
  333.             InsertBTree(t,a[j],s.pt,s.i);      
  334.         printf("   第%d步,插入%d: ",j+1,a[j]);      
  335.         DispBTree(t);      
  336.         printf("\n");      
  337.     }      
  338.     printf("  结果B-树: ");      
  339.     DispBTree(t);      
  340.     printf("\n");      
  341.     printf("删除操作:\n");      
  342.     k=8;      
  343.     DeleteBTree(k,t);      
  344.     printf("  删除%d: ",k);      
  345.     printf("B-树: ");      
  346.     DispBTree(t);      
  347.     printf("\n");      
  348.     k=1;      
  349.     DeleteBTree(k,t);      
  350.     printf("  删除%d: ",k);      
  351.     printf("B-树: ");      
  352.     DispBTree(t);      
  353.     printf("\n");      
  354.     return 0;      
  355. }      


运行结果:



0
 
0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值