1. 程式人生 > >【演算法學習】B-Tree程式設計實現(C++模板類封裝)

【演算法學習】B-Tree程式設計實現(C++模板類封裝)

B-Tree模擬程式設計實現。採用C++模板類封裝。參考《演算法導論(第二版)》第18章 B樹。

實現了B樹的搜尋、插入和刪除的重要操作。

歡迎交流和討論,如有錯誤,還請指出~(E-Mali:[email protected]

BTree.h:

//B-樹程式設計實現
//《演算法導論(第二版)》第18章 B樹
//Author:江南煙雨
//E-Mail:[email protected]

#include <iostream>

//注意:記憶體的釋放操作

//B-Tree節點資料結構定義
template <class KeyT>
struct BTreeNode{
	int n;//當前節點中儲存的關鍵字數
	KeyT *keys;//指向所有關鍵字的指標
	bool isLeaf;//標識當前節點是否是葉子
	struct BTreeNode **childs;//指向所有指向子女的指標
	struct BTreeNode *parent;//指向父節點的指標
};

//B-Tree類封裝
template <class KeyT>
class BTree{
public:
	
private:
	typedef struct BTreeNode<KeyT>* BTreeNodeLink;//指向節點型別的指標型別定義

	BTreeNodeLink T;//根節點
	//每個非根節點至少有t-1個關鍵字,至多2t-1個關鍵字
	int t;//B樹的最小度數

public:
	BTree(int tVal = 2);
	~BTree();
	BTreeNodeLink searchBTree(BTreeNodeLink T,KeyT k,int &index);//在B樹中搜索某關鍵字
	BTreeNodeLink getRoot();//返回當前B樹的根節點
	void insertBTreeNode(KeyT k);//向B樹中插入關鍵字
	void deleteBTreeKey(BTreeNodeLink T,KeyT k);//從B樹中刪除特定關鍵字
	void createBTree(KeyT *keyValues);//建立B樹
	void printBTreeBFS(BTreeNodeLink t);//層次遍歷輸出以t為根的子樹B樹

	void splitChild(BTreeNodeLink x,int i,BTreeNodeLink y);//分裂滿的子節點
	void insertBTreeNonFull(BTreeNodeLink x,KeyT k);//將關鍵字插入到以該非滿節點為根的樹中
	BTreeNodeLink __allocateNode();//產生一個新的節點
	void deleteNode(BTreeNodeLink node);//釋放一個節點所佔的空間(不包括其子女節點所佔空間)
	void deleteTree(BTreeNodeLink t);//刪除一棵B樹所佔空間
};

//建構函式
template <class KeyT>
BTree<KeyT>::BTree(int tVal = 2)
{
	t = tVal;

	typename BTree<KeyT>::BTreeNodeLink x = __allocateNode();
	x->isLeaf = true;
	x->n = 0;
	T = x;
}

//解構函式
template <class KeyT>
BTree<KeyT>::~BTree()
{
	deleteTree(T);

	T = NULL;
}

//函式:依據一組關鍵字值,建立一棵B樹
template <class KeyT>
void BTree<KeyT>::createBTree(KeyT *keyValues)
{
	//遞迴插入關鍵字實現
}

//函式:在B樹中搜索特定關鍵字
//引數解釋:
//T:要搜尋的子樹的根
//k:要搜尋的關鍵字
//index:儲存關鍵字所在節點中關鍵字序列中的索引
//返回值:關鍵字所在的節點
template <class KeyT>
typename BTree<KeyT>::BTreeNodeLink BTree<KeyT>::searchBTree(BTreeNodeLink T,KeyT k,int &index)
{
	if(NULL == T)
	{
		index = -1;
		return NULL;
	}

	int i = 0;
	//搜尋根節點
	while(i < T->n && k > T->keys[i])
		++i;
	//在根節點中已搜尋到相應的關鍵字
	if(i < T->n && k == T->keys[i])
	{
		index = i;
		//cout << "OK : search the key " << k << " successfully ! " << endl;
		//cout << "The index : " << index << endl;
		return T;
	}

	//否則,在子樹中遞迴搜尋
	if(T->isLeaf)//當前子樹根節點已經是葉子,則搜尋失敗
	{
		//cout << "Warnning : search the key " << k << "  failed ! " << endl;
		index = -1;
		return NULL;
	}
	else
	{
		return searchBTree(T->childs[i],k,index);
	}
}

//函式:返回當前B樹的根節點
template <class KeyT>
typename BTree<KeyT>::BTreeNodeLink BTree<KeyT>::getRoot()
{
	return T;
}

//函式:向B樹中插入關鍵字
template <class KeyT>
void BTree<KeyT>::insertBTreeNode(KeyT k)
{
	typename BTree<KeyT>::BTreeNodeLink r = T;
	if (2 * t - 1 == r->n)//根節點滿
	{
		typename BTree<KeyT>::BTreeNodeLink s = __allocateNode();
		T = s;//新根節點
		s->isLeaf = false;
		s->n = 0;
		s->childs[0] = r;
		splitChild(s,0,r);//分裂原根節點
		insertBTreeNonFull(s,k);
	}
	else
		insertBTreeNonFull(r,k);
}

//函式:刪除特定關鍵字
//引數解釋:
//K:要刪除的關鍵字
//TSubTree:要刪除的關鍵字所在節點指標
template <class KeyT>
void BTree<KeyT>::deleteBTreeKey(BTreeNodeLink TSubTree,KeyT k)
{
	if(NULL == TSubTree)
		return;

	//判斷需要刪除的關鍵字是否存在這棵B樹中
	int searchedIndex;
	BTreeNodeLink searchedNode = searchBTree(TSubTree,k,searchedIndex);
	if(NULL == searchedNode)
	{
		cout << "The keyword to be deleted not exist in this B-tree!" << endl;
		return;
	}

	//判斷要被刪除的關鍵字是否在當前節點TSubTree中
	int keyIndex = -1;
	for(int j = 0;j < TSubTree->n;++j)
	{
		if(k == TSubTree->keys[j])
		{
			keyIndex = j;
			break;
		}
	}

	//如果要被刪除的關鍵字存在當前節點中且當前節點是葉節點
	if(keyIndex != -1 && TSubTree->isLeaf == true)
	{
		//直接刪除
		for(int j = keyIndex;j < TSubTree->n - 1;++j)
			TSubTree->keys[j] = TSubTree->keys[j + 1];
		TSubTree->n = TSubTree->n - 1;

		return;
	}
	//如果要被刪除的關鍵字存在當前節點中且當前節點不是葉節點
	else if (keyIndex != -1 && TSubTree->isLeaf == false)
	{
		//被刪除關鍵字所在節點是內節點,進行如下操作
		//尋找前驅
		BTreeNodeLink predecessorNode = TSubTree->childs[keyIndex];
		//尋找後繼
		BTreeNodeLink succeedNode = TSubTree->childs[keyIndex + 1];
		//如果前驅節點中關鍵字數目大於t-1,則以前驅y中最大關鍵字替代被刪除的關鍵字,然後刪除前驅中最大關鍵字
		if(predecessorNode->n > t - 1)
		{
			KeyT predecessorKey = predecessorNode->keys[predecessorNode->n - 1];
			TSubTree->keys[keyIndex] = predecessorKey;
			deleteBTreeKey(predecessorNode,predecessorKey);
		}
		//如果後繼節點中關鍵字數目大於t-1,則以後繼z中最小關鍵字替代被刪除的關鍵字,然後刪除後繼中最小關鍵字
		else if (succeedNode->n > t - 1)
		{
			KeyT succeedKey = succeedNode->keys[0];
			TSubTree->keys[keyIndex] = succeedKey;
			deleteBTreeKey(succeedNode,succeedKey);
		}
		//前驅y和後繼z節點中關鍵字數目都不滿足要求
		else
		{
			//需要將被刪除的關鍵字和z合併進y,使得TSubTree失去k以及指向z的指標,然後從y中刪除k
			predecessorNode->keys[predecessorNode->n] = k;
			for(int j = 0;j < t - 1;++j)
				predecessorNode->keys[t + j] = succeedNode->keys[j];
			predecessorNode->n = 2 * t - 1;
			//修改節點TSubTree
			for(int j = keyIndex;j < TSubTree->n - 1;++j)
				TSubTree->keys[j] = TSubTree->keys[j + 1];
			for(int j = keyIndex + 1;j < TSubTree->n;++j)
				TSubTree->childs[j] = TSubTree->childs[j + 1];
			TSubTree->n = TSubTree->n - 1;

			//如果合併節點後TSubTree中關鍵字數小於t - 1,只可能是TSubTree是根節點
			if(0 == TSubTree->n)//根節點中關鍵字數為0,樹高度下降
				T = TSubTree->childs[keyIndex];

			//釋放節點z所佔空間
			deleteNode(succeedNode);

			deleteBTreeKey(TSubTree->childs[keyIndex],k);
		}
	}
	//如果要被刪除的關鍵字不存在當前節點中
	else
	{
		//首先確定包含要被刪除的關鍵字的子樹的根
		int subTreeIndex;
		BTreeNodeLink searchedNode;
		BTreeNodeLink deletedKeySubT;//包含要被刪除的關鍵字的子樹的根
		for (int j = 0;j < TSubTree->n + 1;++j)
		{
			searchedNode = searchBTree(TSubTree->childs[j],k,subTreeIndex);
			if(searchedNode != NULL)
			{
				deletedKeySubT = TSubTree->childs[j];
				break;
			}
		}

		//包含要被刪除的關鍵字的子樹的根節點關鍵字數少於t,則需要進行調整
		//以保證我們降至一個包含至少關鍵字數為t的節點,然後遞迴進行刪除操作
		if (deletedKeySubT->n < t)
		{
			int index;//當前子樹根節點指標在父節點指標序列中的索引
			for (int i = 0;i < TSubTree->n + 1;++i)
			{
				if(TSubTree->childs[i] == deletedKeySubT)
				{
					index = i;
					break;
				}
			}

			//如果有一個相鄰兄弟包含至少t個關鍵字
			BTreeNodeLink leftBrotherNode = TSubTree->childs[index - 1];//左兄弟節點
			BTreeNodeLink rightBrotherNode = TSubTree->childs[index + 1];//右兄弟節點
			//如果左兄弟節點中有多餘的關鍵字,進行如下操作
			//將左兄弟節點中最大關鍵字上移至雙親節點,而將雙親節點中大於該上移關鍵字的關鍵字下移至被刪除關鍵字所在節點中
			if(index >= 1 && leftBrotherNode->n > t - 1)
			{
				//雙親節點中關鍵字下移
				for(int j = deletedKeySubT->n - 1;j >= 0 ;--j)
					deletedKeySubT->keys[j + 1] = deletedKeySubT->keys[j];
				deletedKeySubT->keys[0] = TSubTree->keys[index - 1];
				deletedKeySubT->n = deletedKeySubT->n + 1;
				//左兄弟節點中關鍵字上移
				TSubTree->keys[index - 1] = leftBrotherNode->keys[leftBrotherNode->n - 1];
				leftBrotherNode->n = leftBrotherNode->n - 1;
			}
			//如果右兄弟節點中有多餘的關鍵字,進行類似的操作
			else if(index < TSubTree->n + 1 && rightBrotherNode->n > t - 1)
			{
				//雙親節點中關鍵字下移
				deletedKeySubT->keys[deletedKeySubT->n] = TSubTree->keys[index];
				deletedKeySubT->n = deletedKeySubT->n + 1;
				//右兄弟節點中關鍵字上移
				TSubTree->keys[index] = rightBrotherNode->keys[0];
				for(int j = 0;j < rightBrotherNode->n - 1;++j)
					rightBrotherNode->keys[j] = rightBrotherNode->keys[j + 1];
				rightBrotherNode->n = rightBrotherNode->n - 1;
			}
			//兩個兄弟節點的關鍵字數都不滿足要求,需要進行合併操作
			else
			{
				//將當前節點、父節點中的一個關鍵字合併到一個兄弟節點(注意有可能沒有左兄弟節點或者有兄弟節點的情況)
				if (index >= 1)//有左兄弟,則合併至左兄弟
				{
					leftBrotherNode->keys[t - 1] = TSubTree->keys[index - 1];//父節點中的關鍵字
					for(int j = 0;j < t - 1;++j)
						leftBrotherNode->keys[t + j] = deletedKeySubT->keys[j];
					leftBrotherNode->n = 2 * t - 1;//合併之後左兄弟節點關鍵字數為2t-1
					for(int j = 0;j < t;++j)
						leftBrotherNode->childs[t + j] = deletedKeySubT->childs[j];
					//更新父節點關鍵字及子女指標序列
					for(int j = index - 1;j < TSubTree->n - 1;++j)
						TSubTree->keys[j] = TSubTree->keys[j + 1];
					TSubTree->n = TSubTree->n - 1;
					for(int j = index;j < TSubTree->n;++j)
						TSubTree->childs[j] = TSubTree->childs[j + 1];

					deleteNode(deletedKeySubT);

					deletedKeySubT = leftBrotherNode;//遞迴刪除操作降至一棵子樹

					////遞迴刪除原節點左兄弟節點中的關鍵字k
					//deleteBTreeKey(leftBrotherNode,k);
				}
				else//否則,合併至右兄弟
				{
					deletedKeySubT->keys[t - 1] = TSubTree->keys[index - 1];//父節點中的關鍵字
					for(int j = 0;j < t - 1;++j)
						deletedKeySubT->keys[t + j] = rightBrotherNode->keys[j];
					deletedKeySubT->n = 2 * t - 1;//合併之後左兄弟節點關鍵字數為2t-1
					for(int j = 0;j < t;++j)
						deletedKeySubT->childs[t + j] = rightBrotherNode->childs[j];
					//更新父節點關鍵字及子女指標序列
					for(int j = index;j < TSubTree->n - 1;++j)
						TSubTree->keys[j] = TSubTree->keys[j + 1];
					TSubTree->n = TSubTree->n - 1;
					for(int j = index + 1;j < TSubTree->n;++j)
						TSubTree->childs[j] = TSubTree->childs[j + 1];

					deleteNode(rightBrotherNode);
					////遞迴刪除原節點左兄弟節點中的關鍵字k
					//deleteBTreeKey(TSubTree,k);
				}
			}
		}
		
		//遞迴在子樹中進行刪除操作
		deleteBTreeKey(deletedKeySubT,k);
	}
}

//函式:層次遍歷輸出以t為根的子樹
template <class KeyT>
void BTree<KeyT>::printBTreeBFS(typename BTree<KeyT>::BTreeNodeLink t)
{
	if(NULL == t)
		return;

	//輸出當前節點所有關鍵字
	cout << "[";
	for(int i = 0;i < t->n;++i)
	{
		cout << t->keys[i];
		if(t->n - 1 != i)
			cout << " ";
	}
	cout << "]" << endl;

	//遞迴輸出所有子樹
	for(int i = 0;i <= t->n;++i)
		printBTreeBFS(t->childs[i]);
}

//函式:分裂滿的子節點
//引數解釋:
//x:一個非滿的內節點
//y:x的一個滿子節點
//i;y的下標
template <class KeyT>
void BTree<KeyT>::splitChild(typename BTree<KeyT>::BTreeNodeLink x, int index,typename BTree<KeyT>::BTreeNodeLink y)
{
	typename BTree<KeyT>::BTreeNodeLink z = __allocateNode();//分裂產生的新節點

	z->isLeaf = y->isLeaf;
	z->n = t - 1;
	//關鍵字賦值
	for(int i = 0;i < t - 1;++i)
		z->keys[i] = y->keys[t + i];
	//非葉節點,子女節點指標賦值
	if(!y->isLeaf)
	{
		for(int i = 0;i < t;++i)
			z->childs[i] = y->childs[t + i];
	}
	z->parent = x;

	//調整原節點的引數
	y->n = t - 1;
	//向後移動子女指標,便於增加一個子女節點指標
	for(int i = x->n;i >= index + 1;--i)
		x->childs[i + 1] = x->childs[i];
	x->childs[index + 1] = z;//插入新子女指標,指向增加的節點z

	//向後移動關鍵字,便於將子女的一個關鍵字上升至父節點
	for(int i = x->n - 1;i >= index;--i)
		x->keys[i + 1] = x->keys[i];
	x->keys[index] = y->keys[t - 1];//關鍵字上移
	x->n = x->n + 1;
}

//函式:將關鍵字插入到根節點非滿的子樹中
template <class KeyT>
void BTree<KeyT>::insertBTreeNonFull(typename BTree<KeyT>::BTreeNodeLink x, KeyT k)
{
	int i = x->n;

	//要插入的節點是葉子節點,直接插入
	if (x->isLeaf)
	{
		//空節點
		if(!i)
		{
			x->keys[0] = k;
			x->n = x->n + 1;
			return;
		}
		//搜尋插入位置,並將關鍵字向後移
		while(i >= 0 && k < x->keys[i - 1])
		{
			x->keys[i] = x->keys[i - 1];
			--i;
		}
		x->keys[i] = k;
		x->n = x->n + 1;
	}
	else{
		//要插入的節點是非葉節點,需要向下遞迴到子樹,將其插入到子樹中適當的葉節點中去
		//尋找要插入的子樹
		while(i > 0 && k < x->keys[i - 1])
			--i;

		//判斷要下降的子節點是否滿
		if (2 * t - 1 == x->childs[i]->n)
		{
			//如果要下降的子樹滿,則分裂
			splitChild(x,i,x->childs[i]);
			//判斷需要下降至哪個子樹上
			if(k > x->keys[i])
				++i;//需要下降至右子樹上
		}
		insertBTreeNonFull(x->childs[i],k);
	}
}

//函式:生成一個新的節點
//返回值:返回指向新節點的指標
template <class KeyT>
typename BTree<KeyT>::BTreeNodeLink BTree<KeyT>::__allocateNode()
{
	typename BTree<KeyT>::BTreeNodeLink newNode = new struct BTreeNode<KeyT>;
	newNode->n = 0;
	newNode->keys = new KeyT[2 * t - 1];//一次性分配2 * t - 1的空間
	newNode->isLeaf = true;
	newNode->childs = new typename BTree<KeyT>::BTreeNodeLink[2 * t];
	newNode->parent = NULL;
	//子女指標初始化
	for(int i = 0;i < 2 * t;++i)
		newNode->childs[i] = NULL;

	return newNode;
}

//函式:釋放一個節點所佔空間
template <class KeyT>
void BTree<KeyT>::deleteNode(typename BTree<KeyT>::BTreeNodeLink node)
{
	delete[] node->keys;
}

//函式:釋放一棵B樹所佔空間
template <class KeyT>
void BTree<KeyT>::deleteTree(typename BTree<KeyT>::BTreeNodeLink t)
{
	if(NULL == t)
		return;

	//是葉節點,直接刪除空間
	if(t->isLeaf)
		delete[] t->keys;
	else
	{
		//遞迴刪除子樹
		for(int i = 0;i < t->n;++i)
			deleteTree(t->childs[i]);

		delete[] t->childs;
	}
}

BTreeTest.cpp:
#include "BTree.h"

#include <iostream>

using namespace std;

int main()
{
	typedef char KeyType;
	const int NUM = 20;
	KeyType keyVals[NUM] = {'a','b','f','g','k','d','h','m','j','e','s','i','r','x','c','l','n','t','u','p'};
	BTree<KeyType> *BTreeObj = new BTree<KeyType>(3);
	BTreeObj->insertBTreeNode(keyVals[0]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[1]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[2]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[3]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[4]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[5]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[6]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[7]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[8]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[9]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[10]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[11]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[12]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[13]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[14]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[15]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[16]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[17]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[18]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());
	BTreeObj->insertBTreeNode(keyVals[19]);
	cout << "Current B-Tree------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	int searchedIndex;
	struct BTreeNode<KeyType> *searchedNode = BTreeObj->searchBTree(BTreeObj->getRoot(),'j',searchedIndex);

	KeyType deletedKey = 'm';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'j';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'g';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'i';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'k';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'l';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'r';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'h';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'n';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'e';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'f';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 's';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'u';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'a';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'b';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'p';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'd';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'c';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 't';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	//delete BTreeObj;

	deletedKey = 'x';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	deletedKey = 'x';
	BTreeObj->deleteBTreeKey(BTreeObj->getRoot(),deletedKey);
	cout << "Current B-Tree after delete " << deletedKey << "------------------------------------ : " << endl;
	BTreeObj->printBTreeBFS(BTreeObj->getRoot());

	return 0;
}

執行結果截圖:




相關推薦

演算法學習B-Tree程式設計實現C++模板封裝

B-Tree模擬程式設計實現。採用C++模板類封裝。參考《演算法導論(第二版)》第18章 B樹。 實現了B樹的搜尋、插入和刪除的重要操作。 歡迎交流和討論,如有錯誤,還請指出~(E-Mali:[email protected]) BTree.h: //B-

演算法總結B+樹的實現

【參考資料】 【B+樹是什麼】 b+樹是b樹的變種。b+樹與b樹最大的不同在於:b+樹的關鍵字數量跟孩子節點數量一致,這與b樹不一樣。並且,b+樹的葉子節點包含有所有關鍵字及其對應資訊,非葉子節點只包含部分關鍵字(這部分關鍵字相當於邊界索引),不含具體資料,下面這幅圖就

python學習——簡單購物系統實現進化版

實現功能有:輸入賬號,密碼。根據賬號密碼會判斷為買家還是賣家,或者是已經被凍結的賬號(密碼輸入三次錯誤賬號就將被凍結)。買家入口:    1.根據序號購買商品    2.每次購買完成,都會顯示本次購買的商品以及餘額    3.若餘額不足,會提示購買失敗    4.按q鍵可退出

資料結構順序佇列的實現C語言

佇列的基本概念及其描述 佇列是一種特殊的線性表,它的特殊性在於佇列的插入和刪除操作分別在表的兩端進行。 插入的那一端稱為隊尾,刪除的那一端稱為隊首。佇列的插入操作和刪除操作分別稱為進隊和出隊。 先進先出(First In First Out) 順序佇列要掌握以下操作:

機器學習k-fold cross validationk-摺疊交叉驗證

交叉驗證的目的:在實際訓練中,模型通常對訓練資料好,但是對訓練資料之外的資料擬合程度差。用於評價模型的泛化能力,從而進行模型選擇。 交叉驗證的基本思想:把在某種意義下將原始資料(dataset)進行分組,一部分做為訓練集(train set),另一部分做為驗證集(valid

資料結構順序棧的實現C語言

棧的基本概念及其描述 棧是一種特殊的線性表,規定它的插入運算和刪除運算均線上性表的同一端進行,進行插入操作和刪除操作的那一端稱為棧頂,另一端稱為棧底。 棧的插入操作和刪除操作分別稱為進棧和出棧。 FILO(First In Last Out)後進先出/先進後出 eg

演算法學習AVL平衡二叉搜尋樹原理及各項操作程式設計實現C++

AVLTree即(Adelson-Velskii-Landis Tree),是加了額外條件的二叉搜尋樹。其平衡條件的建立是為了確保整棵樹的深度為O(nLogn)。平衡條件是任何節點的左右子樹的高度相差不超過1. 在下面的程式碼中,程式設計實現了AVL樹的建立、查詢、插入、

演算法b樹的實現1

【前言】 這個內容是重點,因為它涉及到資料庫的儲存方式,查詢效率等。 先埋坑,到時候有時間再填上去。 還有一篇文章,裡面詳細講述了刪除節點的幾種情況: 【勘誤】我推薦的第二篇文章針對需要合併操作的操作是錯誤的,原因是作者沒有考慮到當父節點不夠數(譬如:5階數,關鍵

演算法學習基於“平均”的隨機分配演算法貪婪,回溯,以按平均工作量隨機分配單位為例

一、背景介紹   在工作中,遇到一個需求:將 N 個單位隨機分配給 n 個人,其中每個單位有對應的工作量,分配時要儘量按工作量平均分給 n 個人,且人員的所屬單位不能包括在被分配的單位中(N >= n)。例如:有三個部門分給兩個人([A]屬於部門2和[B]屬於部門3),部門1的

機器學習接地氣地解釋K-means聚演算法

       俗話說“物以類聚,人以群分”,這句話在K-means聚類演算法裡面得到了充分的繼承。而K-means演算法的實際應用範圍可謂是大到無法估量,基本可以說,只要你想不到,沒有聚類聚不起來的東西!       &nbs

演算法網易程式設計題:暗黑字串組合數

題目 一個字串僅由’A’,’B’,’C’三個字元組成,若字串中不存在’A’,’B’,’C’三個字元相鄰的子串(比如ABC,BAC等),則該字串稱為暗黑字串,否則稱為單純字串。 求長度為L的此種字串中有多少種是暗黑字串? 例子: 字串 AABBA

演算法總結B樹總結

【參考資料】 【B樹解釋】 B樹是一棵樹,不同的是該樹的最多有m個子節點,至少floor(m/2)個子節點(根節點除外,根節點最少可以有兩個子節點。),但是裡面包含關鍵字數量比當前的子節點少1,在沒有子節點的情況下,關鍵字數量在 floor(m/2)-1到m-1之間。

演算法學習切割木棍問題——動態規劃

問題描述: 假設,有一條長度為n的木棍,已知木棍的銷售價格Pi與木棍長度i有關,i = 1,2,3,...n.問,怎樣切割能獲得最大收益。 長度為0的木棍收益肯定是0了,即profit[0] = 0. 切割長度(seg) 1 2 3 4 5 6 7 8 9 10 銷售價格(

機器學習Tensorflow:理解和實現快速風格化影象fast neural style

Neural Style開闢了計算機與藝術的道路,可以將照片風格化為名家大師的畫風。然而這種方法即使使用GPU也要花上幾十分鐘。Fast Neural Style則啟用另外一種思路來快速構建風格化影象,在筆記本CPU上十幾秒就可以風格化一張圖片。我們來看看這是什

機器學習線性迴歸+程式碼實現

參考:《機器學習實戰》 原始碼地址以及資料:https://github.com/JieruZhang/MachineLearninginAction_src 1. 標準線性迴歸(LR) y

機器學習Tensorflow:概率程式設計初步印象

  谷歌對Tensorflow的定位是機器學習庫而不僅僅是深度學習庫。隨著基於Tensorflow的深度概率程式設計庫Edward的發展,Tensorflow踏入概率程式設計領域,與stan、pymc展開了競爭,大大擴充套件了應用範圍。現在來看看基於Tensor

演算法學習求兩陣列求差數Java,三重境界

【題目描述】:兩個陣列,一個A陣列200個,,另一個B陣列199個,兩個陣列亂序,但是差一個數,,,找出差的是那個數。 一。境界1(60分) 【1】遍歷A陣列,對每個數執行【2】操作 【2】遍歷B陣列對比是否存在此數。 參考程式碼如下: /**

機器學習為什麼你程式設計學得越久,就越難入門人工智慧?

有沒有這種感覺,學習程式設計的過程就像在挖一口井,而這口井你可以挖成“web”的形狀,也可以挖成“app”的形狀,還可以挖出“game”的形狀。突然有一天,別人說:挖出“artificial intelligence”的形狀後的井水才是最甜的。於是,你就開

演算法學習字串Hash入門

字串Hash入門 字串Hash可以通俗的理解為,把一個字串轉換為一個整數。 如果我們通過某種方法,將字串轉換為一個整數,就可以便的確定某個字串是否重複出現過,這是最簡單的字串Hash應用情景了。 當然也不難想到,如果有不同的兩個字元串同時Hash

java學習GUI 圖形程式設計

1,相關外掛 對於新手來說,不要在一開始使用此類外掛。當你能自己寫出來程式碼的時候,才是使用此類外掛的時候,為了加快開發效率。加油! 1)eclipse windowbuilder視覺化設計介面 ①安裝 登陸網址:http://eclipse.org/windo