EPANET中的哈希文件——hash.c

/*-----------------------------------------------------------------------------
**   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改的大些,那麼運行效率也就能夠提升了。

相關文章
相關標籤/搜索