/*-----------------------------------------------------------------------------
** hash.c
**
** Implementation of a simple Hash Table for string storage & retrieval
**
** Written by L. Rossman
** Last Updated on 6/19/03
**
** The hash table data structure (HTable) is defined in "hash.h".
** Interface Functions:
** HTcreate() - creates a hash table
** HTinsert() - inserts a string & its index value into a hash table
** HTfind() - retrieves the index value of a string from a table
** HTfree() - frees a hash table
**
*********************************************************************
** NOTE: This is a modified version of the original HASH.C module.
*********************************************************************
*/html
/*-----------------------------------------------------------------------------
** 關於哈希表這一數據結構的介紹,能夠參考博文:
** http://www.cnblogs.com/KingOfFreedom/archive/2012/12/11/2812505.html
**
** 這裏採用的哈希函數是Fletcher's checksum to compute 2-byte hash of string
** 這裏的哈希衝突解決方法是採用上述博文中的第3種方法「鏈地址法」
** 將全部關鍵字爲同義詞的記錄存儲在同一線性鏈表中。該線性鏈表的定義在hash.h中的HTentry
*/算法
#include <malloc.h>
#include <string.h>
#include "hash.h"數據結構
/*
**--------------------------------------------------------------
** 輸入:"ID標識"做爲哈希函數的參數
** 輸出:哈希後的值
** 做用:使用了Fletcher's checksum算法的哈希函數來處理32位長的字符串以得到散列值。
**--------------------------------------------------------------
*/
/* Use Fletcher's checksum to compute 2-byte hash of string */
unsigned int hash(char *str)
{
unsigned int sum1= 0, check1;
unsigned long sum2= 0L;
while( '\0' != *str )
{
sum1 += (*str);
str++;
if ( 255 <= sum1 ) sum1 -= 255;
sum2 += sum1;
}
check1= sum2;
check1 %= 255;
check1= 255 - (sum1+check1) % 255;
sum1= 255 - (sum1+check1) % 255;
return( ( ( check1 << 8 ) | sum1 ) % HTMAXSIZE);
}dom
/*
**--------------------------------------------------------------
** 輸入:無
** 輸出:成功則返回哈希表頭指針
** 做用:建立一個長度爲HTMAXSIZE的哈希表,並初始化
**--------------------------------------------------------------
*/
HTtable *HTcreate()
{
int i;
HTtable *ht = (HTtable *) calloc(HTMAXSIZE, sizeof(HTtable));
if (ht != NULL) for (i=0; i<HTMAXSIZE; i++) ht[i] = NULL;/* Comment by CCR: Here Can Be Better,the Reason is:calloc在動態分配完內存後,自動初始化該內存空間爲零,而malloc不初始化,裏邊數據是隨機的垃圾數據。因此這句能夠註釋掉 */
return(ht);
}函數
/*
**--------------------------------------------------------------
** 輸入:哈希表ht、"ID標識"key、Node中的索引值
** 輸出:成功插入返回1,不然返回0
** 做用:將一個字符串以及索引值插入到哈希表中
**--------------------------------------------------------------
*/
int HTinsert(HTtable *ht, char *key, int data)
{
unsigned int i = hash(key);
struct HTentry *entry;
if ( i >= HTMAXSIZE )
return(0);
entry = (struct HTentry *) malloc(sizeof(struct HTentry));
if (entry == NULL) return(0);//判斷內存是否分配成功
entry->key = key;
entry->data = data;
//將同一hash值的鏈表掛到當前對象entry後面,再將當前對象entry置於隊首
entry->next = ht[i];
ht[i] = entry;
return(1);
}指針
/*
**--------------------------------------------------------------
** 輸入:哈希表、"ID標識"
** 輸出:給出指定"ID標識"在Node中的索引值,若沒找到返回0
** 做用:返回指定"ID標識"在Node中的索引值
**--------------------------------------------------------------
*/
int HTfind(HTtable *ht, char *key)
{
unsigned int i = hash(key);
struct HTentry *entry;
if ( i >= HTMAXSIZE )
return(NOTFOUND);
entry = ht[i];
while (entry != NULL)
{
//哈希衝突處理:鏈地址法
if (strcmp(entry->key,key) == 0 ) return(entry->data);
entry = entry->next;
}
return(NOTFOUND);
}htm
/*
**--------------------------------------------------------------
** 輸入:哈希表、"ID標識"
** 輸出:尋找指定"ID標識"是否存在於哈希表中,若沒找到返回NULL,找到則返回指向"ID標識"的指針
** 做用:判斷指定"ID標識"是否存在於哈希表中
**--------------------------------------------------------------
*/
char *HTfindKey(HTtable *ht, char *key)
{
unsigned int i = hash(key);
struct HTentry *entry;
if ( i >= HTMAXSIZE )
return(NULL);
entry = ht[i];
while (entry != NULL)
{
if ( strcmp(entry->key,key) == 0 ) return(entry->key);
entry = entry->next;
}
return(NULL);
}對象
/*
**--------------------------------------------------------------
** 輸入:哈希表
** 輸出:
** 做用:回收哈希表的內存
**--------------------------------------------------------------
*/
void HTfree(HTtable *ht)
{
struct HTentry *entry,
*nextentry;
int i;
for (i=0; i<HTMAXSIZE; i++)
{
entry = ht[i];
while (entry != NULL)
{
nextentry = entry->next;
free(entry);
entry = nextentry;
}
}
free(ht);
}blog
--------------------------------------------------------索引
哈希表這一數據結構是用內存空間來提升時間效率的算法,理想狀況下(不存在衝突)的哈希算法的時間複雜度是常數O(1)。可是實際狀況是即使開闢了足夠多的一連串的內存空間,若是哈希函數選取不當,仍是會發生衝突。EPANET中的哈希函數的選取是使用了Fletcher's checksum算法的哈希函數來處理32位長的字符串以得到散列值,這個哈希算法的優劣本人還沒法去評斷。可是注意,EPANET中的衝突處理是採用鏈地址法,而EPANET中默認提供的哈希地址個數是HTMAXSIZE個,在hash.h中是這樣定義的#define HTMAXSIZE 1999。若是咱們的模型有5W個左右的節點與管段,那麼這2000個地址空間,平均每一個地址空間會掛有一個長度爲25的線性鏈表。而哈希函數算法不必定這麼優秀,可能某個地址空間掛了一個長度爲上百甚至上千的線性鏈表,那麼查詢效率就低下了。因此,若是運行EPANET的機子有足夠多的內存,好比8G以上,那麼就能夠試着修改hash.h中的#define HTMAXSIZE 1999。將整個1999改的大些,那麼運行效率也就能夠提升了。