算法导论第十八章B树

B树:

BTreeNode.h

#include<iostream>
using namespace std;
class BTree;
class BTreenode
{
private:
	friend BTree;
	//存放键值的数组
	int * pkey;
	//当前有多少键值
	int currentsize;
	//最大存放的键值
	int maxsize;
	BTreenode* parent;
	//存放子女的数组
	BTreenode** pchild;
	//键值初始化数值
	static const int Infinity=10000;
public:
	BTreenode():currentsize(0),maxsize(0),pchild(NULL),parent(NULL){}
	BTreenode(int size):currentsize(0),maxsize(size),pchild(NULL),parent(NULL)
	{
		//关键字为什么要多开辟一个
		pkey=new int [size+1];
		pchild=new BTreenode*[size+1];
		for(int i=0;i<=size;i++)
		{
			pkey[i]=this->Infinity;
			pchild[i]=NULL;
		}
	}
	~BTreenode()
	{
		if(maxsize)
		{
			delete []pkey;
			for(int i=0;i<=maxsize;i++)
			{
				pchild[i]=NULL;
			}
		}
	}
	bool IsFull()
	{
		return currentsize==maxsize;
	}
	int GetKey(int i)
	{
		if(this)
			return this->pkey[i];
		return -1;
	}
	void Destory(BTreenode *node)
	{
		if(node==NULL)
			return ;
		for(int i=0;i<node->maxsize;i++)
		{
			Destory(node->pchild[i]);
		}
		delete node;
	}
};
struct Triple
{
	BTreenode*pfind;
	int pfindkey;
	bool tag;
};

 

BTree.h

#include"BTreenode.h"
class BTree
{
private:
	int Maxsize;
	BTreenode* root;
public:
	BTree(int size):Maxsize(size),root(NULL)
	{}
	~BTree()
	{
		root->Destory(root);
	}
	Triple Search(int num);
	int Size();
	int Size(BTreenode*node);
	bool Insert(int num);
	bool Remove(int num);
	void Print();
	BTreenode*GetParent(int num);
private:
	void InsertKey(BTreenode*pintsert,int n,const int item,BTreenode* pright);
	void PreMove(BTreenode*root,int n);
	void Merge(BTreenode*pleft,BTreenode*pright,BTreenode*parent,int n);
	void LeftAdjust(BTreenode *pright, BTreenode *pparent, int min, int n); 
	void RightAdjust(BTreenode *pleft, BTreenode *pparent, int min, int n);	
    void Print(BTreenode *start, int n = 0);
};
Triple BTree::Search(int num)
{
	BTreenode*p=root,*q=NULL;
	Triple result;
	int i=0;
	while(p)
	{
		i=-1;
		while(num>p->pkey[++i]);
		if(num==p->pkey[i])
		{
			//返回找到的节点
			result.pfind=p;
			//返回找到的位置
			result.pfindkey=i;
			//标记找到此数字
			result.tag=1;
			return result;
		}
		q=p;
		p=p->pchild[i];
	}
	result.pfind=q;
	result.pfindkey=i;
	result.tag=0;
	return result;
}
//在节点pintsert中的n的地方插入关键字item,使该关键字的对应的指针指向pright
void BTree::InsertKey(BTreenode*pintsert,int n,const int item,BTreenode* pright)
{
	pintsert->currentsize++;
	int i;
	for(i=pintsert->currentsize;i>n;i--)
	{
		pintsert->pkey[i]=pintsert->pkey[i-1];
	}
	pintsert->pkey[n]=item;
	pintsert->pchild[n+1]=pright;
	if(pintsert->pchild[n+1])
	{
		//将新插入的节点的父母指向pintsert
		pintsert->pchild[n+1]->parent=pintsert;
		for(i=0;i<=pintsert->pchild[n+1]->currentsize;i++)
		{
			//将新插入的节点的子女的父母指向新插入的节点
			if(pintsert->pchild[n+1]->pchild[i])
			{
				pintsert->pchild[n+1]->pchild[i]->parent=pintsert->pchild[n+1];
			}
		}
	}
}
//插入节点比较麻烦,因为我们将num的节点插入叶子节点之后,如果该节点满了,
//就要把父节点从中间分开,并且将中间节点放到父父节点中,依次往上类推。知道遇到没有满的节点为止
//如果都满了,则插入失败
bool BTree::Insert(int num)
{
	//如果该树是空的,建立根节点
	if(root==NULL)
	{
		root=new BTreenode(this->Maxsize);
		root->currentsize=1;
		root->pkey[1]=root->pkey[0];
		root->pkey[0]=num;
		root->pchild[0]=root->pchild[1]=NULL;
		return 1;
	}
	//如果不是空的,则查找树中有没有该数字
	Triple find=this->Search(num);
	//如果有,则插入失败
	if(find.tag==1)
	{
		cout<<"the "<<num<<"has exit!"<<endl;
		return 0;
	}
	//pinsert为num该插入到该节点
	BTreenode* pinsert=find.pfind,*newnode;
	BTreenode* pright=NULL,*pparent;
	int key=num;
	int n=find.pfindkey;
	while(1)
	{
		//如果pinsert没有满,则直接插入
		if(pinsert->currentsize<pinsert->maxsize-1)
		{
			InsertKey(pinsert,n,key,pright);
			return 1;
		}
		//如果满了则先插入,再将该节点从中间分开,m为要分开的节点
		int m=(pinsert->currentsize+1)/2;
		InsertKey(pinsert,n,key,pright);
		//newnode指向分开的节点的后半部分
		newnode=new BTreenode(this->Maxsize);
		//开始分裂,即将pinsert节点的后半部分分配给newnode
		for(int i=m+1;i<=pinsert->currentsize;i++)
		{
			newnode->pkey[i-m-1]=pinsert->pkey[i];
			newnode->pchild[i-m-1]=pinsert->pchild[i];
			pinsert->pkey[i]=pinsert->Infinity;
			pinsert->pchild[i]=NULL;
		}
		//改变newnode和pinsert节点存储键值的大小
		newnode->currentsize=pinsert->currentsize-m-1;
		pinsert->currentsize=m;
		//改变newnode子节点的父母
		for(int i=0;i<=newnode->currentsize;i++)
		{
			if(newnode->pchild[i])
			{
				newnode->pchild[i]->parent=newnode;
				for(int j=0;j<newnode->pchild[i]->currentsize;j++)
				{
					if(newnode->pchild[i]->pchild[j])
					{
						newnode->pchild[i]->pchild[j]->parent=newnode->pchild[i];
					}
				}
			}
		}
		//改变pinsert节点的父母
		for(int i=0;i<=pinsert->currentsize;i++)
		{
			if(pinsert->pchild[i])
			{
				pinsert->pchild[i]->parent=pinsert;
				for(int j=0;j<pinsert->pchild[i]->currentsize;j++)
				{
					if(pinsert->pchild[i]->pchild[j])
					{
						pinsert->pchild[i]->pchild[j]->parent=pinsert->pchild[i];
					}
				}
			}
		}
		//对刚刚分裂出的第m个键值我们要插入到其父母节点中
		key=pinsert->pkey[m];
		pright=newnode;
		//如果pinsert不是root节点,则从父母节点中找到适合插入m的位置,标记为n,
		//而要插入的节点pinsert这是变成了其父母节点,pright就是newnode
		if(pinsert->parent)
		{
			pparent=pinsert->parent;
			n=-1;
			pparent->pkey[pparent->currentsize]=pparent->Infinity;
			while(key>pparent->pkey[++n]);
			newnode->parent=pinsert->parent;
			pinsert=pparent;
		}
		//如过pinsert是root节点,则新创建一个根节点,并将pinsert和newnode作为root的孩子
		else
		{
			root = new BTreenode(this->Maxsize);
			root->currentsize= 1;
            root->pkey[1] = root->pkey[0];
            root->pkey[0] = key;
			root->pchild[0] = pinsert;
			root->pchild[1] = pright;
            newnode->parent = pinsert->parent = root;
            return 1;
		}
	}
}
//将键值和指针前移,该函数在删除中用到
 void BTree::PreMove(BTreenode *root, int n)
 {
	root->pkey[root->currentsize] = root->Infinity;
    for (int i=n; i<root->currentsize; i++)
	{
        root->pkey[i] = root->pkey[i+1];
		root->pchild[i+1] = root->pchild[i+2];
    }
	root->currentsize--;
 }
 //合并两个子树
 void BTree::Merge(BTreenode *pleft, BTreenode *pparent, BTreenode *pright, int n)
 {
	pleft->pkey[pleft->currentsize] = pparent->pkey[n];
    BTreenode *ptemp;
    
    for (int i=0; i<=pright->currentsize; i++){ //merge the two child tree and the parent
        pleft->pkey[pleft->currentsize+i+1] = pright->pkey[i];
		pleft->pchild[pleft->currentsize+i+1] = pright->pchild[i];
        ptemp = pleft->pchild[pleft->currentsize+i+1];
        if (ptemp){         //change thd right child tree's parent
            ptemp->parent = pleft;
            for (int j=0; j<=ptemp->currentsize; j++){
                if (ptemp->pchild[j]){
                    ptemp->pchild[j]->parent = ptemp;
                }
            }
        }
    }
    
    pleft->currentsize = pleft->currentsize + pright->currentsize + 1;
    delete pright;
    PreMove(pparent, n);    
//    this->Print();
}

void BTree::LeftAdjust(BTreenode *pright, BTreenode *pparent, int min, int n){
    BTreenode *pleft = pparent->pchild[n-1], *ptemp;
    if (pleft->currentsize > min-1){
        for (int i=pright->currentsize+1; i>0; i--){
            pright->pkey[i] = pright->pkey[i-1];
            pright->pchild[i] = pright->pchild[i-1];
        }
        pright->pkey[0] = pparent->pkey[n-1];
        
        pright->pchild[0] = pleft->pchild[pleft->currentsize];
        ptemp = pright->pchild[0];
        if (ptemp){     //change the tree's parent which is moved
            ptemp->parent = pright;
            for (int i=0; i<ptemp->currentsize; i++){
                if (ptemp->pchild[i]){
                    ptemp->pchild[i]->parent = ptemp;
                }
            }
        }
        pparent->pkey[n-1] = pleft->pkey[pleft->currentsize-1];
        pleft->pkey[pleft->currentsize] = pleft->Infinity;
        pleft->currentsize--;
        pright->currentsize++;
    }
    else {
        Merge(pleft, pparent, pright, n-1);
    }
//       this->Print();
}

void BTree::RightAdjust(BTreenode *pleft, BTreenode *pparent, int min, int n){
    BTreenode *pright = pparent->pchild[1], *ptemp;
    if (pright && pright->currentsize > min-1){
        pleft->pkey[pleft->currentsize] = pparent->pkey[0];
        pparent->pkey[0] = pright->pkey[0];
        pleft->pchild[pleft->currentsize+1] = pright->pchild[0];
        ptemp = pleft->pchild[pleft->currentsize+1];
        if (ptemp){         //change the tree's parent which is moved
            ptemp->parent = pleft;
            for (int i=0; i<ptemp->currentsize; i++){
                if (ptemp->pchild[i]){
                    ptemp->pchild[i]->parent = ptemp;
                }
            }
        }
        pright->pchild[0] = pright->pchild[1];
        pleft->currentsize++;
        PreMove(pright,0);
    }
    else {
        Merge(pleft, pparent, pright, 0);
    }
}


bool BTree::Remove(const int item){
    Triple result = this->Search(item);
    if (!result.tag){
        return 0;
    }
    BTreenode *pdel, *pparent, *pmin;
	int n = result.pfindkey;
    pdel = result.pfind;

	if (pdel->pchild[n+1] != NULL){  //change into delete leafnode
        pmin = pdel->pchild[n+1];
        pparent = pdel;
        while (pmin != NULL){
            pparent = pmin;
            pmin = pmin->pchild[0];
        }
        pdel->pkey[n] = pparent->pkey[0];
        pdel = pparent;
        n = 0;
    }

    PreMove(pdel, n); //delete the node

	int min = (this->Maxsize + 1) / 2;
    while (pdel->currentsize < min-1){  //if it is not a BTree, then adjust
        n = 0;
        pparent = pdel->parent;
        if (NULL == pparent)
        {
            return 1;
        }
        while (n<= pparent->currentsize && pparent->pchild[n]!=pdel){
            n++;
        }
        if (!n){
            RightAdjust(pdel, pparent, min, n); //adjust with the parent and the right child tree
        }
        else {
            LeftAdjust(pdel, pparent, min, n); //adjust with the parent and the left child tree
        }
        pdel = pparent;
        if (pdel == root){
            break;
        }
    }
    if (!root->currentsize){         //the root is merged
        pdel = root->pchild[0];
        delete root;
        root = pdel;
        root->parent = NULL;
        for (int i=0; i<root->currentsize; i++){
            if (root->pchild[i]){
                root->pchild[i]->parent = root;
            }
        }
    }
    return 1;
}

void BTree::Print(BTreenode *start, int n){
    if (NULL == start){
        return;
    }
    if (start->pchild[0]){
        Print(start->pchild[0], n+1);    //print the first child tree
    }
    else {
        for (int j=0; j<n; j++){
            cout << "     ";
        }
        cout << "NULL" << endl;
    }

    for (int i=0; i<start->currentsize; i++){   //print the orther child tree
        for (int j=0; j<n; j++){
            cout << "     ";
        }
        cout << start->pkey[i] << "--->" <<endl;
        if (start->pchild[i+1]){
            Print(start->pchild[i+1], n+1);
        }
        else {
            for (int j=0; j<n; j++){
                cout << "     ";
            }
            cout << "NULL" << endl;
        }
    }
}

void BTree::Print(){
    Print(root);
}

int BTree::Size(BTreenode *root){
    if (NULL == root){
        return 0;
    }
    int size=root->currentsize;
    for (int i=0; i<=root->currentsize; i++){
        if (root->pchild[i]){
            size += this->Size(root->pchild[i]);
        }
    }
    return size;
}

int BTree::Size(){
    return this->Size(this->root);
}

BTreenode* BTree::GetParent(const int item){
    Triple result = this->Search(item);
	return result.pfind->parent;
}

 

test.cpp

#include"BTree.h"
int main(){
    BTree btree(3);
    int init[]={1,3,5,7,4,2,8,0,6,9,29,13,25,11,32,55,34,22,76,45
        ,14,26,33,88,87,92,44,54,23,12,21,99,19,27,57,18,72,124,158,234
    ,187,218,382,122,111,222,333,872,123};
    for (int i=0; i<49; i++){
        btree.Insert(init[i]);

    }
    
    btree.Print();
    cout << endl << endl << endl;
    
    Triple result = btree.Search(13);
	cout << result.pfind->GetKey(result.pfindkey) << endl;
    cout << endl << endl << endl;

    for (int i=0; i<49; i++){
        btree.Remove(init[i]);

        btree.Print();
        cout << endl << endl << endl;
                
    }
    
    return 0;
}

 

    原文作者:B树
    原文地址: https://blog.csdn.net/liuzhanchen1987/article/details/7865127
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞