算法练习六 B树上 B树的创建,添加

B树的每个节点需要保存过个值,就需要采用数组,这里使用的是MFC的CArray来保存。经过测试如果调用CArray的SetSize方法预先分配内存,int型100W数量级耗时900ms左右,性能足够我用的。下面直接附上源码。

 

// BTree.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "afxtempl.h" #include <iostream> using namespace std; #define NKEY 3 /* BTNode class */ class BTNode{ public: BTNode(); ~BTNode(); public: void SetLeaf(bool bleaf); BOOL IfLeaf(){ return m_leaf; } public: int m_num; //记录该节点有多少个元素 CArray<int ,int> m_keyAry; CArray<BTNode*,BTNode*> m_subTree; private: bool m_leaf; }; /* @px: 非满的内结点 @py: 满的子结点 py = px->m_subTree[ipos]; */ void BTree_Split_Child( BTNode* px, int ipos, BTNode* py); /* @proot: 指向根结点,该指针可能在函数中被修改,故采用指针的指针 */ void BTree_Insert( BTNode** proot, int key); void BTree_Insert_Nonfull( BTNode* pbt, int key); void LayerOrder(BTNode* proot); int _tmain(int argc, _TCHAR* argv[]) { BTNode* pbtNode = new BTNode(); pbtNode->SetLeaf( TRUE ); //根结点初次创建时为叶子节点 BTNode** proot = &pbtNode; int ary[19] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; for( int i=0; i<sizeof(ary)/sizeof(int); i++) { BTree_Insert( proot, ary[i]); } LayerOrder( *proot ); system("pause"); return 0; } /* BTNode */ BTNode::BTNode() : m_leaf( TRUE ) , m_num(0) { // allocate memory at first time; m_keyAry.SetSize( 2*NKEY -1 ); for( int i=0; i<m_keyAry.GetCount(); i++) { m_keyAry.SetAt(i,-1); } //确定有子树的时候才进行创建,叶节点没有子树的 //m_subTree.SetSize( 2*NKEY ); } BTNode::~BTNode() { m_keyAry.RemoveAll(); m_subTree.RemoveAll(); } // void BTNode::SetLeaf(bool bleaf) { if ( m_leaf && !bleaf ) { m_subTree.SetSize( 2*NKEY ); m_leaf = bleaf; } else { m_leaf = bleaf; } } /* @px: 非满的内结点 @py: 满的子结点 py = px->m_subTree[ipos]; @ipos: 数组下标 */ void BTree_Split_Child( BTNode* px, int ipos, BTNode* py) { BTNode* pz = new BTNode(); pz->SetLeaf( py->IfLeaf() ); pz->m_num = NKEY - 1; //将py的m_keyAry右边的值移动到pz for( int j=0; j<NKEY-1; j++) { int tmp = py->m_keyAry.GetAt( NKEY + j ); // 下标取t -- 2t-2 pz->m_keyAry.SetAt(j, tmp); //将py的关键字设置为-1 py->m_keyAry.SetAt( NKEY+j, -1 ); } //将py的m_subTree右边的值移动到pz if ( !py->IfLeaf() ) { for( int i=0; i<NKEY; i++) { BTNode* ptmp = py->m_subTree.GetAt( NKEY + i); // 下标取 t -- 2t-1 pz->m_subTree.SetAt(i, ptmp); //将py的指针设置为NULL py->m_subTree.SetAt( NKEY+i, NULL ); } } py->m_num = NKEY - 1; //在px中移动一个位置存放py上移的关键字 for( int j=px->m_num-1; j>=ipos; j--) { int tmp = px->m_keyAry.GetAt( j ); px->m_keyAry.SetAt( j+1, tmp); } px->m_keyAry.SetAt( ipos, py->m_keyAry.GetAt( NKEY-1) ); //在px中移动一个位置指向新分裂的节点pz for( int i=px->m_num; i>=ipos+1; i--) { BTNode* pbt = px->m_subTree.GetAt(i); px->m_subTree.SetAt( i+1, pbt); } px->m_subTree.SetAt( ipos+1, pz ); px->m_num++; } /* @proot: 指向根结点,该指针可能在函数中被修改,故采用指针的指针 */ void BTree_Insert( BTNode** proot, int key) { BTNode* pbt = *proot; if ( pbt->m_num == ( 2*NKEY - 1) ) { //创建新的根结点 BTNode* pnew = new BTNode(); pnew->SetLeaf( false ); pnew->m_num = 0; pnew->m_subTree.SetAt(0, pbt); *proot = pnew; BTree_Split_Child( pnew,0, pbt); BTree_Insert_Nonfull( pnew, key); } else { BTree_Insert_Nonfull( pbt, key); } } // void BTree_Insert_Nonfull( BTNode* pbt, int key) { int num = pbt->m_num; //如果pbt为叶子结点 if ( pbt->IfLeaf() ) { int i = num - 1; //转换为下标 //找到一个位置,将Key插入 while( i>=0 && pbt->m_keyAry.GetAt(i) > key ) { int tmp = pbt->m_keyAry.GetAt(i); pbt->m_keyAry.SetAt( i+1, tmp ); i--; } pbt->m_keyAry.SetAt( i+1, key ); pbt->m_num++; } else { //递归进入子结点 int i = num-1; while( i>=0 && pbt->m_keyAry.GetAt(i) > key ) { i--; } i = i+1; BTNode* pchild = pbt->m_subTree.GetAt(i); if ( pchild->m_num == 2*NKEY -1 ) { BTree_Split_Child( pbt, i, pchild ); //判断是否大于从子结点上提升上来的关键字 if ( key > pbt->m_keyAry.GetAt(i) ) { i = i+1; pchild = pbt->m_subTree.GetAt(i); //插入新的子结点 } } BTree_Insert_Nonfull( pchild, key); } } // void LayerOrder(BTNode* proot) { CArray<BTNode*,BTNode*> queue; queue.Add(proot); while( !queue.IsEmpty()) { BTNode* pbt = queue.GetAt(0); queue.RemoveAt(0); for( int i=0; i<pbt->m_num; i++) { cout << pbt->m_keyAry.GetAt(i) << "/t"; } cout << endl; if ( !pbt->IfLeaf() ) { for( int i=0; i<=pbt->m_num; i++) { queue.Add( pbt->m_subTree.GetAt(i) ); } } } } 

你可能感兴趣的:(算法练习六 B树上 B树的创建,添加)