⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 btree.cpp

📁 一个简单的b tree 实现代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <time.h>
#include "btree.hpp"
#include <string>
 
  using namespace std;
/*btree search(typekey, btree,int*); 
btree insert(typekey,btree); 
btree delete_n(typekey,btree); 
int height(btree); 
int count(btree); 
double payload(btree); 
btree deltree(btree); 

static void InternalInsert(typekey, btree); 
static void InsInNode(btree, int); 
static void SplitNode(btree, int); 
static btree NewRoot(btree); 

static void InternalDelete(typekey, btree); 
static void JoinNode(btree, int); 
static void MoveLeftNode(btree t, int); 
static void MoveRightNode(btree t, int); 
static void DelFromNode(btree t, int); 
int print_tree(btree t, int); 
static btree FreeRoot(btree); 

static btree delall(btree); 
static void Error(int,typekey); 
*/

//int btree_disp; /* 查找时找到的键在节点中的位置 */ 
//char * InsValue = NULL; /* 与要插的键相对应的值 */ 
//static int flag; /* 节点增减标志 */
//static int btree_level = 0; /* 多路树的高度 */
//static int btree_count = 0; /* 多路树的键总数 */
//static int node_sum = 0;  /* 多路树的节点总数 */
//static int level; /* 当前访问的节点所处的高度 */
//static btree NewTree; /* 在节点分割的时候指向新建的节点 */
//static typekey InsKey; /* 要插入的键 */

#ifdef key_string
  string null_string="";
#endif
tree::tree()
	{
		 btree_level = 0;
		 btree_count = 0;
		 node_sum = 0;  
		 root=(btree)malloc(sizeof(node));
			memset(root,0x0,sizeof(node));
		}
tree::~tree()
	{


		}

btree tree::search(typekey key, btree t,int *pos)
{
	int i,j,m;
	int l;
	l=btree_level;
	while (l >= 0){

	  /*	for(i=0, j=t->d-1; i<=j; m=(j+i)/2, (key > t->k[m])?(i=m+1):(j=m))
		{i=i;
		}    */
		if(l==0)
	  i=0;else i=1;
		for(;i<t->d ;i++)
		{
			if   (key <= t->k[i])break;
		}

		if (key == t->k [ i ])
		{
		   if(l>0)
		   {
			// i++;
		   }
			else
			{btree_disp = i;
			*pos=i;
			return t;}
		}
		else
	
		 if(l>0 && ( key != t->k [ i ]))
		 i--;
		t = t->p[ i ];
		l--;
	}
	return NULL;
}

btree tree::insert(typekey key, btree t,char* p_str)
{ 		btree temp=NULL,t1;
			t1=t;
	level=btree_level;

		temp=InternalInsert(key, t1,p_str,level);
	if (temp != NULL)  /* 根节点满之后,它被分割成两个半满节点 */
		t1=NewRoot(t,temp);    /* 树的高度增加 */
	  root=t1;
	return t1;
}

btree tree::InternalInsert(typekey key, btree t,char* p_str,int l)
{
	 btree temp=NULL,nt;
	  int i,j,m=0;

	   //检查 key  在 node 的位置
	  if(l==0)
	  i=0;else i=1;
		for(;i<t->d ;i++)
		{
			if   (key <t->k[i])break;

			if (key == t->k[ i]  ) {
				Error(1,key); /* 键已经在树中 */
				flag = 0;
				return NULL;
			}
		}

   if(l==0) //到达底部 是否存在子节点 存在则继续下一层
	{

			if (key == t->k[ i]  ) {
				Error(1,key); /* 键已经在树中 */
				flag = 0;
				return NULL;
			}

		  if(t->d<2*M)
				{
					//如果有空间存放新key,则insert 进node
					InsInLeafNode(key,p_str,t, i);

				}
		  else
			  {
			   //如果无空间则分裂节点,返回新节点指针
			   //返回的新节点temp 的K0 需要insert 到 父节点中
				temp=SplitLeafNode(key,p_str, NULL,t, i);
			  }

		}
	else
		{

				  if(l>0) i--;


				 temp=InternalInsert(key, t->p[i],  p_str,l-1);
				 if(t->k[i]!=t->p[i]->k[0] )//&& temp==NULL
				 t->k[i]=t->p[i]->k[0];
				 nt=temp;
					 if(temp!=NULL)
					 {
						//新增索引节点 若父节点有空间则insert 否则,分裂父节点
								if(t->d<=2*M)
								{
									InsInIndexNode( temp,t, i+1);
									temp=NULL;
								}
							 else
								{
									temp=SplitNode(temp->k[0],p_str,temp, t, i);

									   /*	 if (	nt->p[0]!=NULL)
										 { for(i=0;i<nt->d;i++)
											 {
												nt->k[i]=nt->k[i+1];
												nt->v[i]=nt->v[i+1];
													nt->p[i]=nt->p[i+1];
												}
											 nt->d--;
											 }
											*/
								}

						}
			}
	return temp;
}



/*
* 把一个键和对应的右子树插入一个节点中
*/
void tree::InsInLeafNode(typekey key,char *p_str ,btree t, int d)
{

	 int i;
	/* 把所有大于要插入的键值的键和对应的右子树右移 */
	for(i = t->d; i > d; i--){
		t->k[ i ] = t->k[i-1];
		t->v[ i ] = t->v[i-1];
		t->p[i+1] = t->p[ i ]=NULL;
	}
	/* 插入键和右子树 */

	t->k[ i ] = key;
		t->v[ i ]=p_str;
   //	t->v[ i ] =(char*)malloc(20);
   //	sprintf(t->v[ i ],"%s" ,p_str);

	t->p[ i ] = NULL;
	t->d++;
	t->min=t->k[0];
	}

void tree::InsInIndexNode(btree nt,btree t ,int d)
{
	int i;
	/* 把所有大于要插入的键值的键和对应的右子树右移 */
	for(i = t->d; i > d; i--)
	{
		t->k[ i ] = t->k[i-1];
		t->v[ i ] = t->v[i-1];
		t->p[i] = t->p[ i-1 ];
	}
	/* 插入键和右子树 */
	t->k[ d ] = nt->k[0];
	t->p[d] = nt;
	t->v[ d ] = NULL;
	t->d++;

	/* if (	nt->p[0]!=NULL)
	 { for(i=0;i<nt->d;i++)
	  {
		nt->k[i]=nt->k[i+1];
		nt->v[i]=nt->v[i+1];
		nt->p[i]=nt->p[i+1];

	  }
		  nt->d--;}
	  */

}


void tree::InsInNode(btree t, int d)
{
	int i;
	/* 把所有大于要插入的键值的键和对应的右子树右移 */
	for(i = t->d; i > d; i--){
		t->k[ i ] = t->k[i-1];
		t->v[ i ] = t->v[i-1];
		t->p[i+1] = t->p[ i ];
	}
	/* 插入键和右子树 */
	t->k[ i ] = InsKey;
	t->p[i+1] = NewTree;
	t->v[ i ] = InsValue;
	t->d++;
}

btree tree::SplitNode(typekey key, char *v,btree nt, btree t, int d )
{
	int i,j,k=0;
	btree temp;
	typekey temp_k;
	char *temp_v;
	/* 建立新节点 */
	temp = (btree)malloc(sizeof(node));
	memset( temp,0x0,    sizeof(node));
  /*
	 *   +---+--------+-----+-----+--------+-----+
	 *   | 0 | ...... |  M  | M+1 | ...... |2*M-1|
	 *   +---+--------+-----+-----+--------+-----+
	 *   |<-      M+1     ->|<-        M-1     ->|
	 */
	if (d > M) { /* 要插入当前节点的右半部分 */
		/* 把从 2*M-1 到 M+1 的 M-1 个键值+子树对转移到新节点中,
		 * 并且为要插入的键值+子树空出位置 */


		 for(i=M+1,j=0;i<t->d;i++,j++)
		  {


		  if(t->k[i]>key && k==0)
			{k=1;
				temp->k[j]=key;
				//temp->v[j] =(char*)malloc(20);
				temp->p[j] = nt;
			   //	sprintf(temp->v[j],"%s" ,v);//,strlen(p_str));
				//free(v);
			}else if(i+1==t->d)
				{
				  temp->k[j+1]=key;
				 // temp->v[j+1] =(char*)malloc(20);
				 // sprintf(temp->v[j+1],"%s" ,v);//,strlen(p_str));
				  temp->p[j+1] = nt;
				  //free(v);
				}
				temp->k[j+k]=t->k[ i ];
			   //	temp->v[j+k] = t->v[ i ];
				temp->p[j+k] = t->p[i];
			   #ifdef key_string
			   string s(NULL);
				t->k[ i ]=s;
			   #else
				t->k[ i ]=0;
			   #endif
				t->p[i]=NULL;


		  }



	

	}
	else { /* d <= M */
		/* 把从 2*M-1 到 M 的 M 个键值+子树对转移到新节点中 */
		for(i=M,j=0;i<t->d;i++,j++)
		{
			temp->k[j]=t->k[ i ];
		   //	temp->v[j] = t->v[ i ];
			temp->p[j] = t->p[i];
		  #ifdef key_string

				t->k[ i ]=null_string;
			   #else
				t->k[ i ]=0;
			   #endif
			t->p[i]=NULL;
		}
		//在原来的节点的d位置插入新节点
		for(i=M;i>=d;i--)
		{
			t->k[i+1]=t->k[i];
			t->p[i+1]=t->p[i];
		   //	t->v[i+1]=t->v[i];
		}

		t->k[d]=key;
	   //	t->v[ d ] =(char*)malloc(20);
		t->p[ d ] =nt;
	   //	sprintf(t->v[ d],"%s" ,v);//,strlen(p_str));
	   //	free(v);

	}
	t->d =M+1;
	temp->d = M+1;
	NewTree = temp;
	node_sum++;


	InsKey=  temp->k[0] ;
	// InsValue=  temp->v[0] ;
	// NewTree= temp->p[0] ;
	  pop_key=  temp->k[0];
	  temp->min= pop_key;

   /*	  for(i=0;i<temp->d;i++)
	  {
		temp->k[i]=temp->k[i+1];
		temp->v[i]=temp->v[i+1];
		temp->p[i]=temp->p[i+1];

	  }
	  temp->d--;
	  */


	return temp;
}


btree tree::SplitLeafNode(typekey key, char *v,btree nt, btree t, int d )
{
	int i,j,k=0;
	btree temp=NULL;
	typekey temp_k;
	char *temp_v;
	/* 建立新节点 */
	temp = (btree)malloc(sizeof(node));
	memset( temp,0x0,    sizeof(node));
  /*                     1     2              3
	 *   +---+--------+-----+-----+--------+-----+
	 *   | 0 | ...... |  M  | M+1 | ...... |2*M-1|
	 *   +---+--------+-----+-----+--------+-----+
	 *   |<-      M+1     ->|<-        M-1     ->|
	 */
	if (d > M) { /* 要插入当前节点的右半部分 */
		/* 把从 2*M-1 到 M+1 的 M-1 个键值+子树对转移到新节点中,
		 * 并且为要插入的键值+子树空出位置 */


		 for(i=M+1,j=0;i<t->d;i++,j++)
		  {


		  if(t->k[i]>key && k==0)
			{k=1;
				temp->k[j]=key;

			   //	temp->v[j] =(char*)malloc(20);
			   //	sprintf(temp->v[j],"%s" ,v);
			   temp->v[j]=v;
			}else if(i+1==t->d)
				{
				  temp->k[j+1]=key;
				  temp->v[j+1]=v;
				 // temp->v[j+1] =(char*)malloc(20);
				 // sprintf(temp->v[j+1],"%s" ,v);
				}
				temp->k[j+k]=t->k[ i ];
				temp->v[j+k] = t->v[ i ];
				temp->p[j+k] = t->p[i];
				#ifdef key_string
					t->k[ i ]=null_string;
				#else
				t->k[ i ]=0;
				#endif
				t->p[i]=NULL;


		  }







	}
	else { /* d <= M */
		/* 把从 2*M-1 到 M 的 M 个键值+子树对转移到新节点中 */

		//先将>=m的节点转移到新节点
		for(i=M,j=0;i<t->d;i++,j++)
		{
			temp->k[j]=t->k[ i ];
			temp->v[j] = t->v[ i ];
			temp->p[j] = t->p[i];
			#ifdef key_string
					t->k[ i ]=null_string;
				#else
				t->k[ i ]=0;
				#endif
			t->p[i]=NULL;
		}
		//在原来的节点的d位置插入新节点
		for(i=M;i>=d;i--)
		{
			t->k[i+1]=t->k[i];
			t->p[i+1]=t->p[i];
			t->v[i+1]=t->v[i];
		}

		t->k[d]=key;
		t->v[ d ]=v;
		//t->v[ d ] =(char*)malloc(20);
		t->p[ d ] =NULL;
	   //	sprintf(t->v[ d],"%s" ,v);

		}



	t->d =M+1;
	temp->d = M;
	t->min=t->k[0];
	temp->min=temp->k[0];
	NewTree = temp;
	node_sum++;
	pop_key=temp->k[0];
	return temp;
}



btree tree::delete_n(typekey key, btree t)
{
	level=btree_level;
	btree t1=NULL;
	InternalDelete1(key, t,level);
	if (t->d <= 1)
	/* 根节点的子节点合并导致根节点键的数目随之减少,
	 * 当根节点中没有键的时候,只有它的最左子树可能非空 */
		t=FreeRoot(t);
	   //	root=t;
	return t;
}

void tree::InternalDelete1(typekey key, btree t,int l)
 {  int i,j,m,l1;
	btree nr,nm,nl,t1=NULL;
	int lvl;


	if (l < 0)
	{
		Error(0,key); /* 在整个树中未找到要删除的键 */
		flag = 0;
		return;
	}

	 if(l==0)
	  i=0;else i=1;
		for(;i<t->d ;i++)
		{
			if   (key <t->k[i])break;
		}

		if(l>0)
		{	i--;
			InternalDelete1(key, t->p[ i ] ,l-1);


			 if(t->p[i]->d>0)
			 {
				 if(t->k[i]!=t->p[i]->k[0])
				  t->k[i]=t->p[i]->k[0] ;


					//判断是否需要合并叶子节点    l==1 &&
				if( t->p[i]->d<=M)
				{
					nm =t->p[i];
					if(i==0 && t->d>1)
					{
						nr=t->p[i+1];
						if (nm->d+nr->d<=2*M )
						{
						t1=MergeLeafNode(nm,nr,0,l);
						DelFromNode(t,i+1);
						free(nr);
						t->d--;
						}
						else if(l>1 &&nr->d==2*M+1 &&nm->d<M)
						{
						 t1=MergeLeafNode(nm,nr,2,l);
						 if(t->k[i+1]!=t->p[i+1]->k[0])
								t->k[i+1]=t->p[i+1]->k[0] ;
						}

					}else if (i==t->d-1 && t->d>1)
					{
						nl=t->p[i-1];
						//if (nm->d+nl->d<=2*M )
					   if ((nm->d+nl->d<=2*M ) || ((nm->d+nl->d<=2*M+1 )&&l>1))
						{
							t1=MergeLeafNode(nl,nm,0,l);
							DelFromNode(t,i);
							free(nm);
							t->d--;

						}else if(l>1 && nl->d==2*M+1 &&nm->d<M)
						{
						  t1=MergeLeafNodeBack(nl,nm,M,l);
							if(t->k[i]!=t->p[i]->k[0])
								t->k[i]=t->p[i]->k[0] ;

						}
					}
					else if(  t->d>2)
					{
						nl=t->p[i-1];
						nr=t->p[i+1];
						if ((nm->d+nl->d+nr->d<=4*M)||(nm->d+nl->d+nr->d<=4*M+2 &&l>1))
						{
							if (nl->d<2*M+1)
							{
							  if((nr->d+nm->d<=2*M+1 &&l>0)||(nr->d+nm->d<=2*M))
							  {
								t1=MergeLeafNode(nm,nr,0,l);
								free(nr);
								DelFromNode(t,i+1);
								t->d--;
								if(t->k[i]!=t->p[i]->k[0])
									t->k[i]=t->p[i]->k[0] ;
							  }
							  else
							  {
								t1=MergeLeafNode(nl,nm,2*M-nl->d,l);
								if(nm->d>0)
								{
									t1=MergeLeafNode(nm,nr,0,l);
									free(nr);
									DelFromNode(t,i+1);
									if(t->k[i]!=t->p[i]->k[0])
										t->k[i]=t->p[i]->k[0] ;

								}
								else
								{
									free(nm);
									DelFromNode(t,i);
								}
								t->d--;
							  }
							}
							else
							{
							   t1=MergeLeafNode(nm,nr,0,l);
							   if(nr->d==0)
							   {
									free(nr);
									DelFromNode(t,i+1);
									t->d--;
							   }
							}

						}
						else if(l>0 && nl->d==2*M+1 && nr->d==2*M+1 &&nm->d<M)
						{
							t1=MergeLeafNode(nm,nr,M,l);

						}
					}
					if (l==btree_level&&t->d<=1)
							{root=t1;btree_level--;}

				}
				else if(t->p[i]->d<M)
				{//合并索引节点

				}
			 }
			 else  //节点已被删除
			 {
				DelFromNode(t,i);
				t->d--;
			 }

		 }
		 else if(l==0)
		 {
               i--;
			 if (key == t->k [ i ])
			{
				 if(t->v[ i ]!= NULL)
				   {
						#ifdef key_string
							t->k[ i ]=null_string;
						#else
							t->k[ i ]=0;
						#endif
						free(t->v[i]);
				   }
					DelFromNode(t,i);     //维护父节点索引
					btree_count--;
					t->d--;
					if (t->k[ 0 ]!=t->min)
					t->min=t->k[ 0 ];
				 }
				 else{
				 printf("key not found\n");
				 }
		  }

 }


void tree::InternalDelete(typekey key, btree t,int le)
{
	int i,j,m,l1;
	btree nr,nm,nl,t1=NULL;
	int lvl;


	if (le < 0)
	{
		Error(0,key); /* 在整个树中未找到要删除的键 */
		flag = 0;
		return;
	}
//	for(i=0, j=t->d-1; i<j; m=(j+i)/2, (key > t->k[m])?(i=m+1):(j=m));

	for(i=0;i<t->d ;i++)
		{
			if   (key <= t->k[i])break;
		}
			l1=i;

			if(le>0)               //判断为索引
			 {
				if (key == t->k [ i ] )
				  i++;
				InternalDelete(key, t->p[ i ] ,le-1);

					l1=i;
					if(t->p[ i ]->d<M)
					{
					   if(i>0 && i<t->d)//节点中间 12
					   {
					   // 判断 前节点加后节点的空闲空间 是否足够合并
							if( 4*M-(t->p[ i-1 ]->d +t->p[ i+1 ]->d)<t->p[ i ]->d  )
							{ //无空间 无需合并
							   i=i;
							}
							else
							{
								 nl=t->p[ i-1 ] ;
								 nr=t->p[ i+1];
								 nm=t->p[ i];
								  l1=i;
								if( 2*M-nl->d>nm->d  )
								   {
									t1=MergeNode(nl,nm,0);
									/*for(j=i-1;j<t->d;j++)
									{
										t->k[j]=t->k[j+1];
										t->v[j]=t->v[j+1];
										t->p[j+1]=t->p[j+2];
									}
									 t->p[j]=t->p[j+1];  */
									  t->d--;
								   }
								 else if ( 2*M-nr->d  > nm->d )
								  {
								  t1=MergeNode(nm,nr,0);
								   t->d--;
								   nm=nr;
								   l1=i+1;
								   }
								 else if  ((( 4*M-nl->d -nr->d > nm->d  )  && nl->p[0]==NULL) )
								 {
									MergeNode(nl,nm,0);
									 l1=i;
									if(nl->p[0]!=NULL)
									{t1=MergeNode(nm,nr,0);
									nm=nr;
									l1=i+1;
									}
									 t->d--;
								 }

							  }

					   }
					   else if(i==0)
					   {
							nl=t->p[i] ;
							nm=t->p[i+1];
						  if( ( nl->d+nm->d<2*M) ||((nl->d+nm->d<=2*M)&&(nl->p[0]==NULL)))
						   {
								t1=MergeNode(nl,nm,0);
								 l1=i+1;
								t->d--;
								//后面的节点索引需要前移
									for(j=i;j<t->d;j++)
									{
										t->k[j]=t->k[j+1];
										t->v[j]=t->v[j+1];
										t->p[j+1]=t->p[j+2];
									}
									 t->p[j+1]=t->p[j+2];
									     
								}
					   }
					   else if (i==t->d)
					   {
					   //如左侧有空间 向左合并
					   nl=t->p[ i-1 ] ;
					   nm=t->p[ i];
						 if (( nl->d<2*M - nm->d ) || ((nl->p[0]==NULL)&&( nl->d<=2*M - nm->d ) )   )
						   {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -