/*************************************************************
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,void* pv);
/*
功能:枚舉哈希表的鍵集的回調函數
參數: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 TCHAR* szKey,int keylen,const TCHAR* szVal,int vallen);
/*
功能:添加一個鍵集到哈希文檔
參數:ptr爲哈希表文檔連接件指針,szKey爲鍵名,keylen爲鍵長度,szVal爲鍵值,vallen爲值長度
返回:鍵連接件指針,不存在的鍵名則添加新鍵,已存在的鍵名,鍵值將被覆蓋
*/
XDL_API LINKPTR GetHashEntity(LINKPTR ptr,const TCHAR* szKey,int keylen);
/*
功能:由鍵名檢索鍵
參數:ptr爲哈希表文檔連接件指針,szKey爲鍵名,keylen爲鍵長度
返回:鍵的連接件指針,不存在則返回NULL
*/
XDL_API void DeleteHashEntity(LINKPTR elk);
/*
功能:刪除鍵
參數:鍵的連接件指針
返回:無
*/
XDL_API const TCHAR* GetHashEntityKeyPtr(LINKPTR elk);
/*
功能:取鍵的名稱指針
參數:鍵的連接件指針
返回:鍵名的指針
*/
XDL_API const TCHAR* GetHashEntityValPtr(LINKPTR elk);
/*
功能:取鍵值指針
參數:鍵的連接件指針
返回:鍵值的指針
*/
XDL_API int GetHashEntityKey(LINKPTR elk,TCHAR* buf,int max);
/*
功能:拷貝鍵的名稱
參數:elk爲鍵的連接件指針,buf爲緩衝區指針,max爲緩衝區大小,不包括終結符
返回:實際拷貝的字節數
*/
XDL_API int GetHashEntityVal(LINKPTR elk,TCHAR* buf,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,void* pv);
/*
功能:枚舉哈希文檔的鍵
參數:ptr爲哈希文檔指針,pf爲回調函數,pv爲傳入參數
返回:被枚舉的鍵的計數
*/
XDL_API void HashTableParseOptions(LINKPTR ptr,const TCHAR* options,int len,TCHAR itemfeed,TCHAR linefeed);
/*
功能:從選項串中解析鍵與值集合
參數:ptr爲哈希文檔指針,options爲選項串,格式如: 0~false;1~true;,len爲選項串長度
itemfeed爲名與值的隔離符號,如:~,linefeed爲條目的隔離符號,如:;
返回:無
*/
XDL_API int HashTableFormatOptions(LINKPTR ptr,TCHAR* buf,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*/
TCHAR* szKey; /* entity key, can not be null*/
TCHAR* szVal; /* 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)p - (unsigned int)&(((HashTable*)0)->lk)))
/* restore hash entity struct ptr from link ptr*/
#define HashEntityFromLink(p) ((HashEntity*)((unsigned int)p - (unsigned int)&(((HashEntity*)0)->lk)))
static int HashCode(const TCHAR* szKey,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 TCHAR* szKey,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)
{
HashEntity* pnew;
HashEntity* phe;
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)
{
HashTable* pht;
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(i = 0;i<pht->size;i++)
InitRootLink(pht->pp + i); /*initialize each master root link ptr*/
return &(pht->lk);
}
void DestroyHashTable(LINKPTR ptr)
{
HashTable* pht;
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)
{
HashTable* pht;
HashEntity* phe;
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)
{
HashTable* pht;
HashEntity* phe;
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(i = 0;i<pht->size;i++)
InitRootLink(pht->pp + i); /*set each master root link ptr to initialized state*/
}
LINKPTR AddHashEntity(LINKPTR ptr,const TCHAR* szKey,int keylen,const TCHAR* szVal,int vallen)
{
HashTable* pht;
HashEntity* phe;
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 TCHAR* szKey,int keylen)
{
int nIndex;
unsigned short code;
HashEntity* phe;
HashTable* pht;
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(0 == _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)
{
HashEntity* phe;
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 TCHAR* GetHashEntityKeyPtr(LINKPTR elk)
{
HashEntity* phe;
assert(elk);
assert(elk->tag == lkHashEntity);
phe = HashEntityFromLink(elk);
return phe->szKey;
}
const TCHAR* GetHashEntityValPtr(LINKPTR elk)
{
HashEntity* phe;
assert(elk);
assert(elk->tag == lkHashEntity);
phe = HashEntityFromLink(elk);
return phe->szVal;
}
int GetHashEntityKey(LINKPTR elk,TCHAR* buf,int max)
{
HashEntity* phe;
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,TCHAR* buf,int max)
{
HashEntity* phe;
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)
{
HashEntity* phe;
assert(elk);
assert(elk->tag == lkHashEntity);
phe = HashEntityFromLink(elk);
phe->data = data;
}
unsigned long GetHashEntityData(LINKPTR elk)
{
HashEntity* phe;
assert(elk);
assert(elk->tag == lkHashEntity);
phe = HashEntityFromLink(elk);
return phe->data;
}
int EnumHashEntity(LINKPTR ptr,EnumHashEntityPtr pf,void* pv)
{
HashTable* pht;
HashEntity* phe;
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 TCHAR* options,int len, TCHAR itemfeed,TCHAR linefeed)
{
TCHAR* token;
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,TCHAR* buf,int max,TCHAR itemfeed,TCHAR linefeed)
{
HashTable* pht;
HashEntity* phe;
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
哈希表
哈希表是一個用於快速查找鍵值的數據結構序列,本文的哈希表的實現用於構造字符串鍵和字符串值的哈希序列。主要應用於對象的屬性集合的存取。
哈希表的結構有主散列和子序列構成,主散列是一線性數組,數組的大小爲size,是一個素數,也是哈希函數的模基,數組序號[0...size]即哈希函數的值域,數組存儲的是根連接件,由他維護着相同的哈希值(哈希函數值相同)的節點鏈表。子序列是存儲節點的有序序列,是按各節點關鍵碼升序排列的。哈希值和關鍵碼都是由鍵值通過不同的函數生成的整型值。
查找的路徑爲,根據鍵值的哈希函數值在主散列中定位取得根連接件,然後在此子序列中根據鍵值的關鍵碼篩選,最終通過鍵值的比較來定位到節點。
以下爲哈希表的定義和實現:
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.