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

来源:互联网 发布:矛盾矩阵 编辑:程序博客网 时间:2024/06/05 14:49

/*   

* 烟台大学计算机与控制工程学院  

* 作者:王雪松 

* 完成日期:2016年12月15日    

*   

* 问题描述:

实现B-树的基本操作。基于序列{4, 9, 0, 1, 8, 6, 3, 5, 2, 7}完成测试。 
  (1)创建对应的3阶B-树b,用括号法输出b树。 
  (2)从b中分别删除关键字为8和1的节点,用括号法输出删除节点后的b树。 
* 输入描述:

* 程序输出:

 */ 

代码:

[cpp] view plain copy
  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
原创粉丝点击