#ifndef __HASH_TABLE_H__
#define __HASH_TABLE_H__
#include <afxtempl.h>ide
#define M 200 // 桶的容量。
#define MAX_NUM 32 // 目錄的深度。orm
typedef struct _head{
int g; //全局深度
long number; //節點總數
}Head;it
template <class T>
class TreeNode{
public:
int n; //節點個數
int g; //局部深度
T key[M];
};io
//////////////////////////////////////////////////////////////////
// CHashTable 是M路Hash表class
template <class T>
class CHashTable{
public:
CHashTable(){m_head.g = 1; m_head.number = 0;m_IsUsed = 0;};
~CHashTable(){};sed
public:
BOOL Open(CString& FileName);
void Close();
BOOL InsertNode(T& x);
T * SearchNode(CString& pName);
T * SearchNode(long pID);
CList<T, T&> * SearchNodeList(long pType);//with h_id
CList<T, T&> * SearchNodeListEx(long pPrice);// with t_id
BOOL ChangeNode(T& x);
BOOL ChangeName(CString& pNewName, CString& pOldName);
BOOL ChangeID(long pNewID, long pOldID);
BOOL DeleteNode(CString& pName);
BOOL DeleteNode(long pID);
BOOL DeleteNode(T& x);
long GetCount(){return m_head.number;};List
protected:
long GetHashNum(CString pName);
BOOL AddKeyAtNode(TreeNode<T>& pNode, T& pKey);
BOOL ChangeKeyAtNode(TreeNode<T>& pNode, T& pKey);
BOOL DeleteKeyAtNode(TreeNode<T>& pNode, T& pKey);
BOOL DeleteKeyAtNode(TreeNode<T>& pNode, long pID);
BOOL SearchKeyAtNode(TreeNode<T>& pNode, T& pKey);
BOOL SearchKeyAtNode(TreeNode<T>& pNode, long pID);
void GetListAtNode(TreeNode<T>& pNode, long pID);
void GetListAtNodeEx(TreeNode<T>& pNode, long pID);
long SearchDelete();file
private:
CFile m_hFile, m_iFile;
CList<T, T&> m_List;
T textTEMP;
Head m_head;
int m_IsUsed;di
};while
template <class T>
BOOL CHashTable<T>::Open(CString& FileName)
{
if(m_IsUsed++)return TRUE;
int n;
if((n = FileName.Find(".")) != -1)
FileName = FileName.Left(n);
CString pDataFile = FileName + ".pm";
CString pIndexFile = FileName + ".idx";
if(!m_hFile.Open(pDataFile, CFile::modeReadWrite))
{
m_head.g = 1;
m_head.number = 0;
if(!m_hFile.Open(pDataFile, CFile::modeCreate|CFile::modeReadWrite) ||
!m_iFile.Open(pIndexFile, CFile::modeCreate|CFile::modeReadWrite))
{
AfxMessageBox("Cann't open the file.\n");
return FALSE;
}
else
{
TreeNode<T> pNode;
pNode.g = 1;
pNode.n = 0;
m_hFile.Write(&m_head,sizeof(Head));
m_hFile.Write(&pNode, sizeof(TreeNode<T>));
long p = sizeof(Head);
m_iFile.Write(&p, sizeof(long));
m_hFile.Write(&pNode, sizeof(TreeNode<T>));
p += sizeof(TreeNode<T>);
m_iFile.Write(&p, sizeof(long));
}
}
else {
if(!m_iFile.Open(pIndexFile, CFile::modeReadWrite))
{
AfxMessageBox("Cann't open the file.\n");
return FALSE;
}
m_hFile.Read(&m_head,sizeof(Head));
}
return TRUE;
}
template <class T>
void CHashTable<T>::Close()
{
if(--m_IsUsed)return;
m_hFile.Close();
m_iFile.Close();
}
template <class T>
long CHashTable<T>::GetHashNum(CString pName)
{
if(pName == "")return 0;
wchar_t buffer[100];
CString pTempStr = "";
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pName.LockBuffer(), -1, buffer, pName.GetLength());
for(long i = 0; i < pName.GetLength(); i++)
{
CString temp;
temp.Format("%d", buffer[i]);
if(temp == "0")break;
pTempStr += temp;
}
while(pTempStr.GetLength() < (pTempStr[0] > '4' ?9:10))
pTempStr += "0";
int n = pTempStr.GetLength();
if(pTempStr[0] > '4')
{
if(n % 8 == 0)
n--;
n = n / 8;
pTempStr.Format("%c%c%c%c%c%c%c%c%c", pTempStr[0], pTempStr[5 * n], pTempStr[1 * n], \
pTempStr[6 * n], pTempStr[2 * n], pTempStr[7 * n], pTempStr[3 * n], \
pTempStr[8 * n], pTempStr[4 * n]);
}
else
{
if(n % 9 == 0)
n--;
n = n / 9;
pTempStr.Format("%c%c%c%c%c%c%c%c%c%c", pTempStr[0], pTempStr[5 * n], pTempStr[1 * n], \
pTempStr[6 * n], pTempStr[2 * n], pTempStr[7 * n], pTempStr[3 * n], \
pTempStr[8 * n], pTempStr[4 * n], pTempStr[9 * n]);
}
DWORD h = atol(pTempStr.LockBuffer());
h>>=(MAX_NUM - m_head.g);
return h;
}
template <class T>
BOOL CHashTable<T>::AddKeyAtNode(TreeNode<T>& pNode, T& pKey)
{
if( pNode.n >= M)return FALSE;
int n = pNode.n - 1;
while((pKey < pNode.key[n])&&(n >= 0))
{
memcpy(&pNode.key[n + 1], &pNode.key[n], sizeof(T));
n--;
}
memcpy(&pNode.key[n + 1], &pKey, sizeof(T));
pNode.n++;
return TRUE;
}
template <class T>
BOOL CHashTable<T>::ChangeKeyAtNode(TreeNode<T>& pNode, T& pKey)
{
int n = 0;
while(pKey > pNode.key[n])n++;
if(pKey == pNode.key[n])
{
memcpy(&pNode.key[n], &pKey, sizeof(T));
return TRUE;
}
return FALSE;
}
template <class T>
BOOL CHashTable<T>::DeleteKeyAtNode(TreeNode<T>& pNode, T& pKey)
{
int n = 0;
while(pKey > pNode.key[n])n++;
if(n < pNode.n)
{
for(; n < pNode.n; n++)
memcpy(&pNode.key[n], &pNode.key[n + 1], sizeof(T));
pNode.n--;
return TRUE;
}
return FALSE;
}
template <class T>
BOOL CHashTable<T>::DeleteKeyAtNode(TreeNode<T>& pNode, long pID)
{
int n = 0;
while((pID != pNode.key[n].id)&&(n < pNode.n))n++;
if(pID == pNode.key[n].id)
{
for(; n < pNode.n; n++)
memcpy(&pNode.key[n], &pNode.key[n + 1], sizeof(T));
pNode.n--;
return TRUE;
}
return FALSE;
}
template <class T>
BOOL CHashTable<T>::SearchKeyAtNode(TreeNode<T>& pNode, T& pKey)
{
int n = 0;
while(pKey > pNode.key[n])n++;
if(pKey == pNode.key[n])
{
memcpy(&textTEMP, &pNode.key[n], sizeof(T));
return TRUE;
}
return FALSE;
}
template <class T>
BOOL CHashTable<T>::SearchKeyAtNode(TreeNode<T>& pNode, long pID)
{
int n = 0;
while((pID != pNode.key[n].id)&&(n < pNode.n))n++;
if(pID == pNode.key[n].id)
{
memcpy(&textTEMP, &pNode.key[n], sizeof(T));
return TRUE;
}
return FALSE;
}
template <class T>
void CHashTable<T>::GetListAtNode(TreeNode<T>& pNode, long pID)
{
for(int n = 0; n < pNode.n; n++)
if(pID == pNode.key[n].h_id)
m_List.AddTail(pNode.key[n]);
}
template <class T>
void CHashTable<T>::GetListAtNodeEx(TreeNode<T>& pNode, long pID)
{
for(int n = 0; n < pNode.n; n++)
if(pID == pNode.key[n].t_id)
m_List.AddTail(pNode.key[n]);
}
template <class T>
long CHashTable<T>::SearchDelete()
{
/* long p=sizeof(Head);
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);
return m_hFile.GetPosition();
}
template <class T>
BOOL CHashTable<T>::InsertNode(T& x)
{
TreeNode<T> a, b;
long p;
long pHash = GetHashNum(CString(x.name));
m_iFile.Seek(pHash * sizeof(long), CFile::begin);
m_iFile.Read(&p, sizeof(long));
m_hFile.Seek(p, CFile::begin);
m_hFile.Read(&a, sizeof(TreeNode<T>));
if(!AddKeyAtNode(a, x))
{
long qHash = (long)m_iFile.GetLength();
a.g++;
b.n = 0;
b.g = a.g;
if(a.g > m_head.g)
{
m_head.g++;
long * buffer = (long *)malloc(qHash);
m_iFile.Seek(0L, CFile::begin);
m_iFile.Read(buffer, qHash);
m_iFile.Seek(0L, CFile::end);
m_iFile.Write(buffer, qHash);
free(buffer);
}
for(int i = a.n - 1; i >= 0; i--)
{
qHash = GetHashNum(CString(a.key[i].name));
if(qHash == pHash)
{
AddKeyAtNode(b, a.key[i]);
DeleteKeyAtNode(a, a.key[i]);
}
}
qHash = GetHashNum(CString(x.name));
if(qHash == pHash)
AddKeyAtNode(b, x);
else
AddKeyAtNode(a, x);
p = SearchDelete();
m_hFile.Seek(p, CFile::begin);
m_hFile.Write(&b, sizeof(TreeNode<T>));
m_iFile.Seek(pHash * sizeof(long), CFile::begin);
m_iFile.Write(&p, sizeof(long));
}
else
{
m_hFile.Seek(p, CFile::begin);
m_hFile.Write(&a, sizeof(TreeNode<T>));
}
m_head.number++;
m_hFile.Seek(0L, CFile::begin);
m_hFile.Write(&m_head,sizeof(Head));
return TRUE;
}
template <class T>
BOOL CHashTable<T>::DeleteNode(T& x)
{
TreeNode<T> a;
long p;
long pHash = GetHashNum(CString(x.name));
m_iFile.Seek(pHash * sizeof(long), CFile::begin);
m_iFile.Read(&p, sizeof(long));
m_hFile.Seek(p, CFile::begin);
m_hFile.Read(&a, sizeof(TreeNode<T>));
if(DeleteKeyAtNode(a, x))
{
m_hFile.Seek(p, CFile::begin);
m_hFile.Write(&a, sizeof(TreeNode<T>));
return TRUE;
}
return FALSE;
}
template <class T>
BOOL CHashTable<T>::DeleteNode(CString& pName)
{
TreeNode<T> a;
long p;
long pHash = GetHashNum(pName);
m_iFile.Seek(pHash * sizeof(long), CFile::begin);
m_iFile.Read(&p, sizeof(long));
m_hFile.Seek(p, CFile::begin);
m_hFile.Read(&a, sizeof(TreeNode<T>));
T pKey;
strcpy(pKey.name, pName.LockBuffer());
if(DeleteKeyAtNode(a, pKey))
{
m_hFile.Seek(p, CFile::begin);
m_hFile.Write(&a, sizeof(TreeNode<T>));
return TRUE;
}
return FALSE;
}
template <class T>
BOOL CHashTable<T>::DeleteNode(long pID)
{
TreeNode<T> a;
long pHash = sizeof(Head);
do{
m_hFile.Seek(pHash, CFile::begin);
m_hFile.Read(&a, sizeof(TreeNode<T>));
if(DeleteKeyAtNode(a, pID))
{
m_hFile.Seek(pHash, CFile::begin);
m_hFile.Write(&a, sizeof(TreeNode<T>));
return TRUE;
}
pHash += sizeof(TreeNode<T>);
}while(pHash < (long)m_hFile.GetLength());
return FALSE;
}
template <class T>
T * CHashTable<T>::SearchNode(CString& pName)
{
TreeNode<T> a;
long p;
long pHash = GetHashNum(pName);
m_iFile.Seek(pHash * sizeof(long), CFile::begin);
m_iFile.Read(&p, sizeof(long));
m_hFile.Seek(p, CFile::begin);
m_hFile.Read(&a, sizeof(TreeNode<T>));
T pKey;
strcpy(pKey.name, pName.LockBuffer());
if(SearchKeyAtNode(a, pKey))
{
return &textTEMP;
}
return NULL;
}
template <class T>
T * CHashTable<T>::SearchNode(long pID)
{
TreeNode<T> a;
long pHash = sizeof(Head);
do{
m_hFile.Seek(pHash, CFile::begin);
m_hFile.Read(&a, sizeof(TreeNode<T>));
if(SearchKeyAtNode(a, pID))
{
return &textTEMP;
}
pHash += sizeof(TreeNode<T>);
}while(pHash < (long)m_hFile.GetLength());
return NULL;
}
template <class T>
CList<T, T&> * CHashTable<T>::SearchNodeList(long pType)//with h_id
{
TreeNode<T> a;
long pHash = sizeof(Head);
m_List.RemoveAll();
do{
m_hFile.Seek(pHash, CFile::begin);
m_hFile.Read(&a, sizeof(TreeNode<T>));
GetListAtNode(a, pType);
pHash += sizeof(TreeNode<T>);
}while(pHash < (long)m_hFile.GetLength());
return &m_List;
}
template <class T>
CList<T, T&> * CHashTable<T>::SearchNodeListEx(long pType)//with t_id
{
TreeNode<T> a;
long pHash = sizeof(Head);
m_List.RemoveAll();
do{
m_hFile.Seek(pHash, CFile::begin);
m_hFile.Read(&a, sizeof(TreeNode<T>));
GetListAtNodeEx(a, pType);
pHash += sizeof(TreeNode<T>);
}while(pHash < (long)m_hFile.GetLength());
return &m_List;
}
template <class T>
BOOL CHashTable<T>::ChangeNode(T& x)
{
TreeNode<T> a;
long p;
long pHash = GetHashNum(CString(x.name));
m_iFile.Seek(pHash * sizeof(long), CFile::begin);
m_iFile.Read(&p, sizeof(long));
m_hFile.Seek(p, CFile::begin);
m_hFile.Read(&a, sizeof(TreeNode<T>));
if(ChangeKeyAtNode(a, x))
{
m_hFile.Seek(p, CFile::begin);
m_hFile.Write(&a, sizeof(TreeNode<T>));
return TRUE;
}
return FALSE;
}
template <class T>
BOOL CHashTable<T>::ChangeName(CString& pNewName, CString& 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>
BOOL CHashTable<T>::ChangeID(long pNewID, long pOldID)
{
T temp, * p;
if((p = SearchNode(pOldID)) != NULL)
{
memcpy(&temp, p, sizeof(T));
DeleteNode(temp);
temp.id = pNewID;
InsertNode(temp);
return TRUE;
}
else
return FALSE;
}
#endif