哈希表

哈希表是一個用於快速查找鍵值的數據結構序列,本文的哈希表的實現用於構造字符串鍵和字符串值的哈希序列。主要應用於對象的屬性集合的存取。
哈希表的結構有主散列和子序列構成,主散列是一線性數組,數組的大小爲size,是一個素數,也是哈希函數的模基,數組序號[0...size]即哈希函數的值域,數組存儲的是根連接件,由他維護着相同的哈希值(哈希函數值相同)的節點鏈表。子序列是存儲節點的有序序列,是按各節點關鍵碼升序排列的。哈希值和關鍵碼都是由鍵值通過不同的函數生成的整型值。
查找的路徑爲,根據鍵值的哈希函數值在主散列中定位取得根連接件,然後在此子序列中根據鍵值的關鍵碼篩選,最終通過鍵值的比較來定位到節點。
       以下爲哈希表的定義和實現:
 
 
  /*************************************************************
       EasySoft xdl v3.0
 
       (c) 2003-2006 EasySoft Corporation. All Rights Reserved.
 
       @doc xdl.rtf: hash table
 
       @module       hashtable.h | hash table interface file
 
       @devnote PowerSuite 2003.01 - 2006.12
*************************************************************/
 
#ifndef _HASHTABLE_H
#define _HASHTABLE_H
 
#include "xdl/link.h"
#include "xdl/xdldef.h"
 
#ifdef __cplusplus
extern "C" {
#endif
 
/*define enum hash entity callback function */
typedef int (*EnumHashEntityPtr)(LINKPTR ent,voidpv);
/*
功能:枚舉哈希表的鍵集的回調函數
參數:ent爲本次枚舉的鍵,pv回傳的參數
返回:零值繼續枚舉,非零值終止枚舉
*/
 
XDL_API LINKPTR CreateHashTable(int nSize);
/*
功能:創建哈希文檔
參數:表大小,可以爲MIN_PRIM,MID_PRM,MAX_PRIM
返回:哈希表文檔連接件指針
*/
 
XDL_API void DestroyHashTable(LINKPTR ptr);
/*
功能:銷燬哈希文檔
參數:哈希表文檔連接件指針
返回:無
*/
 
XDL_API void CopyHashTable(LINKPTR ptrDest,LINKPTR ptrSrc);
/*
功能:拷貝哈希文檔
參數:ptrDest爲目的哈希文檔指針,ptrSrc爲源哈希文檔指針
返回:無
*/
 
XDL_API void ClearHashTable(LINKPTR ptr);
/*
功能:清除哈希文檔鍵值集合
參數:哈希表文檔連接件指針
返回:無
*/
 
XDL_API LINKPTR       AddHashEntity(LINKPTR ptr,const TCHARszKey,int keylen,const TCHARszVal,int vallen);
/*
功能:添加一個鍵集到哈希文檔
參數:ptr爲哈希表文檔連接件指針,szKey爲鍵名,keylen爲鍵長度,szVal爲鍵值,vallen爲值長度
返回:鍵連接件指針,不存在的鍵名則添加新鍵,已存在的鍵名,鍵值將被覆蓋
*/
 
XDL_API LINKPTR       GetHashEntity(LINKPTR ptr,const TCHARszKey,int keylen);
/*
功能:由鍵名檢索鍵
參數:ptr爲哈希表文檔連接件指針,szKey爲鍵名,keylen爲鍵長度
返回:鍵的連接件指針,不存在則返回NULL
*/
 
XDL_API void DeleteHashEntity(LINKPTR elk);
/*
功能:刪除鍵
參數:鍵的連接件指針
返回:無
*/
 
XDL_API const TCHARGetHashEntityKeyPtr(LINKPTR elk);
/*
功能:取鍵的名稱指針
參數:鍵的連接件指針
返回:鍵名的指針
*/
 
XDL_API const TCHARGetHashEntityValPtr(LINKPTR elk);
/*
功能:取鍵值指針
參數:鍵的連接件指針
返回:鍵值的指針
*/
 
XDL_API int GetHashEntityKey(LINKPTR elk,TCHARbuf,int max);
/*
功能:拷貝鍵的名稱
參數:elk爲鍵的連接件指針,buf爲緩衝區指針,max爲緩衝區大小,不包括終結符
返回:實際拷貝的字節數
*/
 
XDL_API int GetHashEntityVal(LINKPTR elk,TCHARbuf,int max);
/*
功能:拷貝鍵值
參數:elk爲鍵的連接件指針,buf爲緩衝區指針,max爲緩衝區大小,不包括終結符
返回:實際拷貝的字節數
*/
 
XDL_API void SetHashEntityData(LINKPTR elk,unsigned long data);
/*
功能:設置鍵的額外數據
參數:elk爲鍵的連接件指針,data爲額外數據
返回:無
*/
 
XDL_API unsigned long GetHashEntityData(LINKPTR elk);
/*
功能:取得鍵的額外數據
參數:elk爲鍵的連接件指針
返回:額外數據
*/
 
XDL_API int       EnumHashEntity(LINKPTR ptr,EnumHashEntityPtr pf,voidpv);
/*
功能:枚舉哈希文檔的鍵
參數:ptr爲哈希文檔指針,pf爲回調函數,pv爲傳入參數
返回:被枚舉的鍵的計數
*/
 
XDL_API void HashTableParseOptions(LINKPTR ptr,const TCHARoptions,int len,TCHAR itemfeed,TCHAR linefeed);
/*
功能:從選項串中解析鍵與值集合
參數:ptr爲哈希文檔指針,options爲選項串,格式如: 0~false;1~true;,len爲選項串長度
itemfeed爲名與值的隔離符號,如:~,linefeed爲條目的隔離符號,如:;
返回:無
*/
 
XDL_API int HashTableFormatOptions(LINKPTR ptr,TCHARbuf,int max,TCHAR itemfeed,TCHAR linefeed);
/*
功能:將哈希文檔的鍵值集合格式化成選項串
參數:ptr爲哈希文檔指針,buf爲緩衝區指針,max爲緩衝區長度,itemfeed爲名與值的隔離符號,如:~,linefeed爲條目的隔離符號,如:;
返回:無
*/
 
XDL_API int HashTableFormatOptionsSize(LINKPTR ptr,TCHAR itemfeed,TCHAR linefeed);
/*
功能:測試將哈希文檔的鍵值集合格式化成選項串所需要的緩衝區大小,不包括終結符
參數:ptr爲哈希文檔指針,itemfeed爲名與值的隔離符號,如:~,linefeed爲條目的隔離符號,如:;
返回:無
*/
 
#ifdef __cplusplus
}
#endif
 
#endif 
/*_HASHTABLE_H*/
 
/*************************************************************
       EasySoft xdl v3.0
 
       (c) 2003-2006 EasySoft Corporation. All Rights Reserved.
 
       @doc xdl.rtf: hash table
 
       @module       hashtable.c | hash table implement file
 
       @devnote PowerSuite 2003.01 - 2006.12
*************************************************************/
 
/************************************************************
*************************************************************/
 
#include "xdl/hashtable.h"
#include "xdl/xdlutil.h"
 
typedef struct _HashEntity{
       
LINK lk;               /* entity self link component*/
       
TCHARszKey;            /* entity key, can not be null*/
       
TCHARszVal;             /* entity value*/
       
unsigned short code/* entity key code*/
       
unsigned long data;       /* entiry data for XdlFree use*/
}HashEntity;
 
typedef struct _HashTable{
       
LINK lk;               /* hash table self link component*/
       
LINKPTR pp;                 /* hash table master root link ptr array*/
       
int size;                 /* root link ptr array size, is prim value*/
}HashTable;
 
/* restore hash table struct ptr from link ptr*/
#define HashTableFromLink(p) ((HashTable*)((unsigned int)- (unsigned int)&(((HashTable*)0)->lk))) 
/* restore hash entity struct ptr from link ptr*/
#define HashEntityFromLink(p) ((HashEntity*)((unsigned int)- (unsigned int)&(((HashEntity*)0)->lk))) 
 
static int HashCode(const TCHARszKey,int keylen,int nPrim)
{
       
unsigned int sum;
       
int i;
 
       
assert(szKey);
       
assert(nPrim 0);
 
       
if(keylen == -1)
              
keylen _tcslen(szKey);
 
       
sum 0;
       
for(i=0;i<keylen;i++)
       {
              
sum += (unsigned int)(szKey[i]);
       }
       
return sum nPrim;
}
 
static unsigned short KeyCode(const TCHARszKey,int keylen)
{
       
unsigned short code;
       
int i;
 
       
assert(szKey);
 
       
if(keylen == -1)
              
keylen _tcslen(szKey);
 
       
code 0;
       
for(i=0;i<keylen;i++)
       {
              
code += (unsigned short)(szKey[i]);
              
code code << 1;
       }
       
return code ;
}
 
void _InsertEntity(LINKPTR root,LINKPTR ptrEntity)
{
       
HashEntitypnew;
       
HashEntityphe;
       
LINKPTR plk;
       
       
assert(root && root->tag == lkRoot);
       
assert(ptrEntity && ptrEntity->tag == lkHashEntity);
       
       
pnew HashEntityFromLink(ptrEntity);
       
plk GetFirstLink(root);
       
while(plk)
       {
              
phe HashEntityFromLink(plk);
              
if(phe->code pnew->code)
                     
break;/*find the prev link*/
              
              
plk GetNextLink(plk);
       }
       
       
if(plk == NULL)
       {
              
InsertLink(root,LINK_LAST,ptrEntity);
       }
else
       
{
              
InsertLinkBefore(root,plk,ptrEntity);
       }
}
 
LINKPTR CreateHashTable(int nSize)
{
       
HashTablepht;
       
int i;
       
       
assert(nSize 0);
       
pht = (HashTable*)XdlAlloc(1,sizeof(HashTable));
       
pht->lk.tag lkHashTable;
       
pht->size nSize;
       
pht->pp = (LINKPTR)XdlAlloc(nSize,sizeof(LINK));
       
for(0;i<pht->size;i++)
              
InitRootLink(pht->pp i);       /*initialize each master root link ptr*/
 
       
return &(pht->lk);
}
 
void DestroyHashTable(LINKPTR ptr)
{
       
HashTablepht;
 
       
assert(ptr);
       
assert(ptr->tag == lkHashTable);
 
       
pht HashTableFromLink(ptr);
       
ClearHashTable(ptr);       /*XdlFree all hash eitity*/
 
       
XdlFree(pht->pp);
       
XdlFree(pht);
}
 
void CopyHashTable(LINKPTR ptrDest,LINKPTR ptrSrc)
{
       
HashTablepht;
       
HashEntityphe;
       
LINKPTR plk;
       
int i;
       
       
assert(ptrDest && ptrDest->tag == lkHashTable);
       
assert(ptrSrc && ptrSrc->tag == lkHashTable);
 
       
pht HashTableFromLink(ptrSrc);
       
for(i=0;i<pht->size;i++)
       {
              
plk GetFirstLink(&((pht->pp)[i]));
              
while(plk != NULL)
              {
                     
phe HashEntityFromLink(plk);
 
                     
AddHashEntity(ptrDest,phe->szKey,-1,phe->szVal,-1);
 
                     
plk GetNextLink(plk);
              }
       }
}
 
void ClearHashTable(LINKPTR ptr)
{
       
HashTablepht;
       
HashEntityphe;
       
LINKPTR plk,pre;
       
int i;
 
       
assert(ptr);
       
assert(ptr->tag == lkHashTable);
 
       
pht HashTableFromLink(ptr);
 
       
for(i=0;i<pht->size;i++)
       {
              
plk GetFirstLink(&(pht->pp[i]));
              
while(plk)
              {
                     
pre plk;
                     
plk GetNextLink(plk);
                     
                     
phe HashEntityFromLink(pre);
                     
XdlFree(phe->szKey);
                     
if(phe->szVal)
                            
XdlFree(phe->szVal);
                     
XdlFree(phe);
              }
       }
 
       
for(0;i<pht->size;i++)
              
InitRootLink(pht->pp i);       /*set each master root link ptr to initialized state*/
}
 
LINKPTR       AddHashEntity(LINKPTR ptr,const TCHARszKey,int keylen,const TCHARszVal,int vallen)
{
       
HashTablepht;
       
HashEntityphe;
       
LINKPTR plk;
       
int nIndex;
 
       
assert(ptr);
       
assert(ptr->tag == lkHashTable);
 
       
if(IsNullStr(szKey) || keylen == 0)
              
return NULL;
 
       
pht HashTableFromLink(ptr);
       
/*first to find entity with the key*/
       
plk GetHashEntity(ptr,szKey,keylen);
       
if(plk != NULL)           /*if exist then to replace the entiry value*/
       
{
              
phe HashEntityFromLink(plk);
              
              
if(phe->szVal != NULL)
              {
                     
XdlFree(phe->szVal);
                     
phe->szVal NULL;
              }
              
if(!IsNullStr(szVal) && vallen)
              {
                     
if(vallen == -1)
                            
vallen _tcslen(szVal);
                     
phe->szVal = (TCHAR*)XdlAlloc(vallen 1,sizeof(TCHAR));
                     
_tcsncpy(phe->szVal,szVal,vallen);
              }
       }
else       /*if not exist then to add new entity with key and value*/
       
{     
              
phe = (HashEntity*)XdlAlloc(1,sizeof(HashEntity));
              
phe->lk.tag lkHashEntity;
              
              
if(keylen == -1)
                     
keylen _tcslen(szKey);
              
              
phe->szKey = (TCHAR*)XdlAlloc(keylen 1,sizeof(TCHAR));
              
_tcsncpy(phe->szKey,szKey,keylen);
              
phe->code KeyCode(szKey,keylen);
              
              
if(!IsNullStr(szVal) && vallen)
              {
                     
if(vallen == -1)
                            
vallen _tcslen(szVal);
                     
phe->szVal = (TCHAR*)XdlAlloc(vallen 1,sizeof(TCHAR));
                     
_tcsncpy(phe->szVal,szVal,vallen);
              }
              
              
nIndex HashCode(phe->szKey,keylen,pht->size);
              
plk = &((pht->pp)[nIndex]);
              
              
/*insert entity to list by key's asc order*/
              
_InsertEntity(plk,&phe->lk);
       }
 
       
return &(phe->lk);
}
 
LINKPTR       GetHashEntity(LINKPTR ptr,const TCHARszKey,int keylen)
{
       
int nIndex;
       
unsigned short code;
       
HashEntityphe;
       
HashTablepht;
       
LINKPTR plk;
 
       
assert(ptr);
       
assert(ptr->tag == lkHashTable);
 
       
if(IsNullStr(szKey) || keylen == 0)
              
return NULL;
 
       
pht HashTableFromLink(ptr);
 
       
if(keylen == -1)
              
keylen _tcslen(szKey);
 
       
/*first to calc master root link ptr array position by the key's hash code */
       
nIndex HashCode(szKey,keylen,pht->size);
       
code KeyCode(szKey,keylen);
       
/*then to compare the entity key in the ordered list*/
       
plk GetFirstLink(&((pht->pp)[nIndex]));
       
while(plk != NULL)
       {
              
phe HashEntityFromLink(plk);
              
if(phe->code == code)
              {
                     
if(== _tcsncmp(phe->szKey,szKey,keylen))
                     {
                            
if((int)_tcslen(phe->szKey) == keylen)
                                   
return plk;
                     }
              }
else if(phe->code code)
                     
return NULL;
       
              
plk GetNextLink(plk);
       }
 
       
return NULL;
}
 
void DeleteHashEntity(LINKPTR elk)
{
       
HashEntityphe;
 
       
assert(elk);
       
assert(elk->tag == lkHashEntity);
 
       
phe HashEntityFromLink(elk);
       
/*delete link ptr from list*/
       
DeleteLink(GetRootLink(elk),elk);
 
       
XdlFree(phe->szKey);
       
if(phe->szVal)
              
XdlFree(phe->szVal);
       
XdlFree(phe);
}
 
const TCHARGetHashEntityKeyPtr(LINKPTR elk)
{
       
HashEntityphe;
 
       
assert(elk);
       
assert(elk->tag == lkHashEntity);
       
phe HashEntityFromLink(elk);
       
return phe->szKey;
}
 
const TCHARGetHashEntityValPtr(LINKPTR elk)
{
       
HashEntityphe;
 
       
assert(elk);
       
assert(elk->tag == lkHashEntity);
       
phe HashEntityFromLink(elk);
       
return phe->szVal;
}
 
int GetHashEntityKey(LINKPTR elk,TCHARbuf,int max)
{
       
HashEntityphe;
       
int len;
 
       
assert(elk);
       
assert(elk->tag == lkHashEntity);
       
assert(buf && max >= 0);
       
phe HashEntityFromLink(elk);
       
len _tcslen(phe->szKey);
       
len = (len max)? len max;
       
_tcsncpy(buf,phe->szKey,len);
       
buf[len] = _T('/0');
 
       
return len;
}
 
int GetHashEntityVal(LINKPTR elk,TCHARbuf,int max)
{
       
HashEntityphe;
       
int len;
 
       
assert(elk);
       
assert(elk->tag == lkHashEntity);
       
assert(buf && max >= 0);
       
phe HashEntityFromLink(elk);
       
if(phe->szVal == NULL)
       {
              
buf[0] = _T('/0');
              
return 0;
       }
else
       
{
              
len _tcslen(phe->szVal);
              
len = (len max)? len max;
              
_tcsncpy(buf,phe->szVal,len);
             
buf[len] = _T('/0');
              
return len;
       }
}
 
void       SetHashEntityData(LINKPTR elk,unsigned long data)
{
       
HashEntityphe;
 
       
assert(elk);
       
assert(elk->tag == lkHashEntity);
 
       
phe HashEntityFromLink(elk);
       
phe->data data;
}
 
unsigned long GetHashEntityData(LINKPTR elk)
{
       
HashEntityphe;
 
       
assert(elk);
       
assert(elk->tag == lkHashEntity);
 
       
phe HashEntityFromLink(elk);
       
return phe->data;
}
 
int EnumHashEntity(LINKPTR ptr,EnumHashEntityPtr pf,voidpv)
{
       
HashTablepht;
       
HashEntityphe;
       
LINKPTR plk;
       
int i,count;
       
       
assert(ptr);
       
assert(ptr->tag == lkHashTable);
 
       
pht HashTableFromLink(ptr);
       
count 0;
       
for(i=0;i<pht->size;i++)
       {
              
plk GetFirstLink(&((pht->pp)[i]));
              
while(plk != NULL)
              {
                     
phe HashEntityFromLink(plk);
                     
count ++;
 
                     
if(pf == NULL)
                     {
                            
plk GetNextLink(plk);
                            
continue;
                     }
                     
/*if callback function return none zero value then to break enum*/
                     
if((*pf)(plk,pv))
                            
return count;
 
                     
plk GetNextLink(plk);
              }
       }
       
return count;
}
 
XDL_API void HashTableParseOptions(LINKPTR ptr,const TCHARoptions,int lenTCHAR itemfeed,TCHAR linefeed)
{
       
TCHARtoken;
       
TCHAR *key,*val;
       
int keylen,vallen;
 
       
assert(ptr && ptr->tag == lkHashTable);
 
       
ClearHashTable(ptr);
 
       
if(options == NULL || len == 0)
              
return;
 
       
if(len == -1)
              
len _tcslen(options);
 
       
token = (TCHAR*)options;
       
while(token != options len)
       {
              
key token;
              
while(*token != itemfeed && *token != _T('/0'))
                     
token ++;
              
keylen token key;
 
              
if(token == _T('/0'))
                     
break;
 
              
token ++; /*skip item feed*/
              
              
val token;
              
while(*token != linefeed && *token != _T('/0'))
                     
token ++;
              
vallen token val;
 
              
AddHashEntity(ptr,key,keylen,val,vallen);
 
              
if(*token == _T('/0'))
                     
break;
 
              
token ++; /*skip line feed*/
       
}
}
 
int HashTableFormatOptions(LINKPTR ptr,TCHARbuf,int max,TCHAR itemfeed,TCHAR linefeed)
{
       
HashTablepht;
       
HashEntityphe;
       
LINKPTR plk;
       
int i,total,len;
       
       
assert(ptr);
       
assert(ptr->tag == lkHashTable);
 
       
pht HashTableFromLink(ptr);
       
total 0;
 
       
for(i=0;i<pht->size;i++)
       {
              
plk GetFirstLink(&((pht->pp)[i]));
              
while(plk != NULL)
              {
                     
phe HashEntityFromLink(plk);
 
                     
len _tcslen(phe->szKey) + ((phe->szVal)? _tcslen(phe->szVal) : 0) + 2/*include itemfeed and linefeed*/
                     
if(total len max)
                            
return -1;
                     
if(buf)
                            
_stprintf(buf total,_T("%s%c%s%c"),phe->szKey,itemfeed,((phe->szVal)? phe->szVal _T("")),linefeed);
                     
total += len;
 
                     
plk GetNextLink(plk);
              }
       }
       
return total;
}
 
int HashTableFormatOptionsSize(LINKPTR ptr,TCHAR itemfeed,TCHAR linefeed)
{
       
return HashTableFormatOptions(ptr,NULL,MAX_INT,itemfeed,linefeed);
}
collected by barenx
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章