这个B-树结构将数据存在磁盘上,M是一个自定义的常量,通常定义成200效率会高一些。每个节点内部采用插入排序法,这种排序法适用于节点数较小或者数据已经很有序的情况。
#ifndef __BOOKTREE_H__
#define __BOOKTREE_H__
#include <time.h>
template <class T>
class TreeNode{
public:
int n;
long a[M+1];
T key[M];
};
typedef struct _head{
long root;
long number;
}TreeHead;
//
// CBookTree 是M路B-树, 每个结点类型必须包含
// char * name;
// long id;
// 这两种结构, 并且依据 name 排序, 依据 name和 id进行查找,
// 依据 name插入结点, 删除结点, 修改结点.
// 其余结构不限.
template <class T>
class CBookTree{
public:
CBookTree(){ m_root.root = -1; m_root.number = 0; m_IsUsed = 0;};
~CBookTree(){while(m_IsUsed)Close();};
public:
BOOL Open(const char * FileName);
BOOL Open(CString& pFileName);
void Close();
BOOL InsertNode(T& x);
T * SearchNode(const char *name);
T * SearchNode(long curs);
CList<T, T&> * SearchNodeList(long group);
BOOL ChangeNode(T& x,BOOL dayon);
BOOL ChangeName(const char * pNewName, const char * pOldName);
BOOL DeleteNode(const char *name);
long GetCount();
protected:
Triple Search(const char *name);
BOOL SearchNode(long curs,long p);
void SearchNodeList(long group, long p);
long SearchDelete();
private:
CFile m_hFile;
CList<T, T&> m_List;
T textTEMP;
long ptr[20];
TreeHead m_root;
int m_pTop;
int m_IsUsed;
};
template <class T>
BOOL CBookTree<T>::Open(const char * FileName)
{
if(m_IsUsed++)return TRUE;
if(!m_hFile.Open(FileName, CFile::modeReadWrite))
{
m_root.root=0;
if(!m_hFile.Open(FileName, CFile::modeCreate|CFile::modeReadWrite))
{AfxMessageBox("Cann't open the file.\n");return FALSE;}
else m_hFile.Write(&m_root,sizeof(TreeHead));
}
else m_hFile.Read(&m_root,sizeof(TreeHead));
return TRUE;
}
template <class T>
BOOL CBookTree<T>::Open(CString& FileName)
{
if(m_IsUsed++)return TRUE;
if(!m_hFile.Open(FileName, CFile::modeReadWrite))
{
m_root.root=0;
if(!m_hFile.Open(FileName, CFile::modeCreate|CFile::modeReadWrite))
{AfxMessageBox("Cann't open the file.\n");return FALSE;}
else m_hFile.Write(&m_root,sizeof(TreeHead));
}
else m_hFile.Read(&m_root,sizeof(TreeHead));
return TRUE;
}
template <class T>
void CBookTree<T>::Close()
{
if(--m_IsUsed)return;
m_hFile.Close();
}
template <class T>
Triple CBookTree<T>::Search(const char *name)
{
long p,q;
int i=0,j=0;
TreeNode<T> a;
Triple t;
t.p=0L;t.i=0;t.j=0;m_pTop=0;
ptr[0]=0L;
for(p=m_root.root,q=0L;p;q=p,p=a.a[i],ptr[++m_pTop]=q)
{
m_hFile.Seek(p,CFile::begin);
m_hFile.Read(&a,sizeof(TreeNode<T>));
for(i=0;i<a.n;i++)
if(strcmp(name,a.key[i].name)<=0)break;
if( i>=a.n )continue;
if(strcmp(a.key[i].name,name)==0)
{
t.p=p;t.i=i;t.j=1;
return(t);
}
}
t.p=q;t.i=i;t.j=0;
return(t);
}
template <class T>
long CBookTree<T>::SearchDelete()
{
long p=sizeof(TreeHead);
int q;
while(p != (long)m_hFile.GetLength())
{
m_hFile.Seek(p, CFile::begin);
m_hFile.Read(&q,sizeof(int));
if(q==0)return(p);
p+=sizeof(TreeNode<T>);
}
m_hFile.Seek(0L, CFile::end);
p=(long)m_hFile.GetPosition();
return(p);
}
template <class T>
BOOL CBookTree<T>::InsertNode(T& x)
{
Triple s;
T K;
time_t ltime;
struct tm *today;
long _A,p,q,r;
int i;
TreeNode<T> a, b;
s=Search(x.name);
if(s.j)return FALSE;
time( <ime );today = localtime( <ime );
x.day=today->tm_mday;x.month=today->tm_mon+1;
x.year=today->tm_year+1900;
_A=0L;p=s.p;r=0L;q=0L;
m_root.number++;
for(memcpy(&K,&x,sizeof(T));p;memcpy(&K,&a.key[M/2-1],sizeof(T)),_A=q,p=ptr[--m_pTop])
{
m_hFile.Seek(p,CFile::begin);
m_hFile.Read(&a,sizeof(TreeNode<T>));
i=a.n;
while(strcmp(K.name,a.key[i-1].name)<0)
{
memcpy(&a.key[i],&a.key[i-1],sizeof(T));
a.a[i+1]=a.a[i];
if(--i<1)break;
}
memcpy(&a.key[i],&K,sizeof(T));
a.a[i+1]=_A;a.n++;
if(a.n<=M-1)
{
m_hFile.Seek(p, CFile::begin);
m_hFile.Write(&a,sizeof(TreeNode<T>));
m_hFile.Seek(0L, CFile::begin);
m_hFile.Write(&m_root,sizeof(TreeHead));
m_hFile.Flush();
return(TRUE);
}
q=SearchDelete();
m_hFile.Seek(q, CFile::begin);
for(i=0;i<M/2;i++)
{
memcpy(&b.key[i],&a.key[i+M/2],sizeof(T));
b.a[i]=a.a[i+M/2-1];
}
b.a[i]=a.a[i+M/2-1];b.n=M-M/2;a.n=M/2-1;
m_hFile.Seek(p, CFile::begin);
m_hFile.Write(&a,sizeof(TreeNode<T>));
m_hFile.Seek(q, CFile::begin);
m_hFile.Write(&b,sizeof(TreeNode<T>));
}
r=SearchDelete();
m_hFile.Seek(r, CFile::begin);
b.n=1;b.a[0]=m_root.root;memcpy(&b.key[0],&K,sizeof(T));
b.a[1]=_A;m_root.root=r;
m_hFile.Seek(r, CFile::begin);
m_hFile.Write(&b,sizeof(TreeNode<T>));
m_hFile.Seek(0L, CFile::begin);
m_hFile.Write(&m_root,sizeof(TreeHead));
m_hFile.Flush();
return(TRUE);
}
template <class T>
BOOL CBookTree<T>::ChangeNode(T& x,BOOL dayon)
{
Triple t;
time_t ltime;
struct tm *today;
TreeNode<T> a;
if(dayon)
{
time( <ime );today = localtime( <ime );
x.day=today->tm_mday;x.month=today->tm_mon+1;
x.year=today->tm_year+1900;
}
t=Search(x.name);if(!t.j)return(FALSE);
m_hFile.Seek(t.p, CFile::begin);
m_hFile.Read(&a,sizeof(TreeNode<T>));
memcpy(&a.key[t.i],&x,sizeof(T));
m_hFile.Seek(t.p, CFile::begin);
m_hFile.Write(&a,sizeof(TreeNode<T>));
return TRUE;
}
template <class T>
BOOL CBookTree<T>::ChangeName(const char * pNewName, const char * pOldName)
{
T s_temp;
T * p;
p = SearchNode(pOldName);
if(p == NULL)return FALSE;
memcpy(&s_temp, p, sizeof(T));
DeleteNode(pOldName);
sprintf(s_temp.name,"%s",pNewName);
InsertNode(s_temp);
return TRUE;
}
template <class T>
T * CBookTree<T>::SearchNode(const char *name)
{
long p;
int i;
TreeNode<T> a;
for(p=m_root.root;p;p=a.a[i])
{
m_hFile.Seek(p, CFile::begin);
m_hFile.Read(&a,sizeof(TreeNode<T>));
for(i=0;i<a.n;i++)
if(strcmp(name,a.key[i].name)<=0)break;
if( i>=a.n )continue;
if(strcmp(a.key[i].name,name)==0)
{
memcpy(&textTEMP,&a.key[i],sizeof(T));
return &textTEMP;
}
}
return NULL;
}
template <class T>
BOOL CBookTree<T>::DeleteNode(const char *name)
{
Triple s;
long z,p,y;
int i,j;
TreeNode<T> a, b, c;
s=Search(name);
if(!s.j)return(FALSE);
p=s.p;i=s.i;
m_hFile.Seek(p, CFile::begin);
m_hFile.Read(&a,sizeof(TreeNode<T>));
if(a.a[0])
{
for(y=a.a[i+1];;ptr[++m_pTop]=y,y=b.a[0])
{
m_hFile.Seek(y, CFile::begin);
m_hFile.Read(&b,sizeof(TreeNode<T>));
if(!b.a[0])break;
}
memcpy(&a.key[i],&b.key[0],sizeof(T));
m_hFile.Seek(p, CFile::begin);
m_hFile.Write(&a,sizeof(TreeNode<T>));
p=y;i=0;
m_hFile.Seek(p, CFile::begin);
m_hFile.Read(&a,sizeof(TreeNode<T>));
}
for(j=i;j<a.n;j++)
{
memcpy(&a.key[j],&a.key[j+1],sizeof(T));
a.a[j]=a.a[j+1];
}
a.n--;
while((a.n<(M/2-1))&&p!=m_root.root)
{
z=ptr[m_pTop--];
m_hFile.Seek(z, CFile::begin);
m_hFile.Read(&c,sizeof(TreeNode<T>));
for(j=0;j<=c.n;j++)if(c.a[j]==p)break;
if(j<c.n)
{
y=c.a[j+1];
m_hFile.Seek(y, CFile::begin);
m_hFile.Read(&b,sizeof(TreeNode<T>));
if(b.n>=M/2)
{
memcpy(&a.key[a.n-1],&c.key[j],sizeof(T));
a.a[a.n]=b.a[0];a.n++;
memcpy(&c.key[j],&b.key[0],sizeof(T));
for(i=0;i<b.n;i++)
{
memcpy(&b.key[i],&b.key[i+1],sizeof(T));
b.a[i]=b.a[i+1];
}
b.n--;
m_hFile.Seek(p, CFile::begin);
m_hFile.Write(&a,sizeof(TreeNode<T>));
m_hFile.Seek(y, CFile::begin);
m_hFile.Write(&b,sizeof(TreeNode<T>));
m_hFile.Seek(z, CFile::begin);
m_hFile.Write(&c,sizeof(TreeNode<T>));
return TRUE;
}
memcpy(&a.key[a.n],&c.key[j],sizeof(T));
a.a[a.n]=b.a[0];
for(i=1;i<=b.n;i++)
{
memcpy(&a.key[a.n+i],&b.key[i-1],sizeof(T));
a.a[a.n+i]=b.a[i];
}
a.n+=b.n+1;b.n=0;
m_hFile.Seek(p, CFile::begin);
m_hFile.Write(&a,sizeof(TreeNode<T>));
m_hFile.Seek(y, CFile::begin);
m_hFile.Write(&b,sizeof(TreeNode<T>));
a.n=c.n-1;a.a[j-1]=c.a[j-1];p=z;
for(i=0;i<j-1;i++)
{
memcpy(&a.key[i],&c.key[i],sizeof(T));
a.a[i]=c.a[i];
}
for(i=j;i<c.n;i++)
{
memcpy(&a.key[i-1],&c.key[i-1],sizeof(T));
a.a[i-1]=c.a[i-1];
}
}
else {
y=c.a[j-1];
m_hFile.Seek(y, CFile::begin);
m_hFile.Read(&b,sizeof(TreeNode<T>));
if(b.n>=M/2)
{
for(i=a.n;i>0;i--)
{
memcpy(&a.key[i],&a.key[i-1],sizeof(T));
a.a[i]=a.a[i-1];
}
memcpy(&a.key[0],&c.key[j-1],sizeof(T));
a.a[0]=b.a[b.n];a.n++;
memcpy(&c.key[j-1],&b.key[b.n-1],sizeof(T));b.n--;
m_hFile.Seek(p, CFile::begin);
m_hFile.Write(&a,sizeof(TreeNode<T>));
m_hFile.Seek(y, CFile::begin);
m_hFile.Write(&b,sizeof(TreeNode<T>));
m_hFile.Seek(z, CFile::begin);
m_hFile.Write(&c,sizeof(TreeNode<T>));
return TRUE;
}
memcpy(&b.key[b.n],&c.key[j-1],sizeof(T));
b.a[b.n]=a.a[0];
for(i=1;i<=a.n;i++)
{
memcpy(&b.key[b.n+i],&a.key[i-1],sizeof(T));
b.a[b.n+i]=a.a[i];
}
b.n+=a.n+1;a.n=0;
m_hFile.Seek(p, CFile::begin);
m_hFile.Write(&a,sizeof(TreeNode<T>));
m_hFile.Seek(y, CFile::begin);
m_hFile.Write(&b,sizeof(TreeNode<T>));
a.n=c.n-1;p=z;
for(i=0;i<=j;i++)
{
memcpy(&a.key[i],&c.key[i],sizeof(T));
a.a[i]=c.a[i];
}
}
}
m_hFile.Seek(p, CFile::begin);
m_hFile.Write(&a,sizeof(TreeNode<T>));
if(!a.n)
{
m_root.root=a.a[0];
m_hFile.Seek(0L, CFile::begin);
m_hFile.Write(&m_root,sizeof(TreeHead));
}
return TRUE;
}
template <class T>
T * CBookTree<T>::SearchNode(long curs)
{
if(SearchNode(curs, m_root.root))
return &textTEMP;
return NULL;
}
template <class T>
BOOL CBookTree<T>::SearchNode(long curs,long p)
{
TreeNode<T> a;
int i;
if(p==0L)return FALSE;
m_hFile.Seek(p, CFile::begin);
m_hFile.Read(&a,sizeof(TreeNode<T>));
for(i=0;i<a.n;i++)
if(a.key[i].id == curs)
{
memcpy(&textTEMP,&a.key[i],sizeof(T));
return TRUE;
}
for(i=0;i<=a.n;i++)
if(SearchNode(curs,a.a[i]))
return TRUE;
return FALSE;
}
template <class T>
CList<T, T&> * CBookTree<T>::SearchNodeList(long group)
{
m_List.RemoveAll();
SearchNodeList(group, m_root.root);
return &m_List;
}
template <class T>
void CBookTree<T>::SearchNodeList(long group,long p)
{
TreeNode<T> a;
int i;
if(p==0L)return;
m_hFile.Seek(p, CFile::begin);
m_hFile.Read(&a,sizeof(TreeNode<T>));
for(i=0;i<a.n;i++)
if(a.key[i].h_id == group)
m_List.AddTail(a.key[i]);
for(i=0;i<=a.n;i++)
SearchNodeList(group,a.a[i]);
}
template <class T>
long CBookTree<T>::GetCount()
{
return m_root.number + 1;
}
#endif