/*-----------------------------------------------------------------------------
**   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.
*********************************************************************
*/

/*-----------------------------------------------------------------------------
**   关于哈希表这一数据结构的介绍,可以参考博文:
**   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);
}

/*
**--------------------------------------------------------------
**  输入:无
**  输出:成功则返回哈希表头指针
**  作用:创建一个长度为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);
}

/*
**--------------------------------------------------------------
**  输入:哈希表、"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);
}

--------------------------------------------------------

哈希表这一数据结构是用内存空间来提高时间效率的算法,理想情况下(不存在冲突)的哈希算法的时间复杂度是常数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改的大些,那么运行效率也就可以提高了。

EPANET中的哈希文件——hash.c的更多相关文章

  1. EPANET中读取INPUT文件的函数文件——INPUT3.C

    /* ********************************************************************** INPUT3.C -- Input data par ...

  2. EPANET中读取INPUT文件的函数文件——INPUT1.C/INPUT2.C/INPUT3.C

    首先介绍下这3个文件的关系:可以说INPUT1.C的函数粒度最大,它的函数getdata()就完成了整个INPUT文件数据的读入,该函数又调用了INPUT2.C中的部分函数,INPUT2.C文件中的函 ...

  3. Java集合类中的哈希总结

    JAVA集合类中的哈希总结 目 录 1.哈希表 2.Hashtable.HashMap.ConcurrentHashMap.LinkedHashMap.TreeMap区别 3.Hashtable.Ha ...

  4. 哈希表(Hash)的应用

    $hs=@() #定义数组 $hs=@{} #定义Hash表,使用哈希表的键可以直接访问对应的值,如 $hs["王五"] 或者 $hs.王五 的值为 75 $hs=@''@ #定义 ...

  5. Java中的哈希

    Java中的哈希 前言 在开发中经常用到HashMap.HashSet等与哈希有关的数据结构,一直只知道这些哈希的数据结构不保证顺序,不清楚具体什么情况.所以在这里大致总结一下.   Java的Has ...

  6. ORACLE中Scalar subquery Caching的hash table大小测试浅析

      前阵子总结了这篇"ORACLE当中自定义函数性优化浅析"博客,里面介绍了标量子查询缓存(scalar subquery caching),如果使用标量子查询缓存,ORACLE会 ...

  7. 词典(二) 哈希表(Hash table)

    散列表(hashtable)是一种高效的词典结构,可以在期望的常数时间内实现对词典的所有接口的操作.散列完全摒弃了关键码有序的条件,所以可以突破CBA式算法的复杂度界限. 散列表 逻辑上,有一系列可以 ...

  8. 文件hash、上传,实现文件上传重复验证

    在平台开发中,我们往往对性能要求十分严苛,每一个字段.接口都有严格的要求. 系统中文件流操作十分占用资源,这里为大家介绍对文件上传进行哈希校验---同一文件只允许上传一次到服务器,其他的上传只要指向文 ...

  9. Python 中的哈希表

    Python 中的哈希表:对字典的理解   有没有想过,Python中的字典为什么这么高效稳定.原因是他是建立在hash表上.了解Python中的hash表有助于更好的理解Python,因为Pytho ...

随机推荐

  1. CentOS下httpd下php 连接mysql 本机可以,127.0.0.1不能访问

    你看到的这个文章来自于http://www.cnblogs.com/ayanmw php代码很简单: $server="127.0.0.1"; println("Begi ...

  2. 奇怪吸引子---YuWang

    奇怪吸引子是混沌学的重要组成理论,用于演化过程的终极状态,具有如下特征:终极性.稳定性.吸引性.吸引子是一个数学概念,描写运动的收敛类型.它是指这样的一个集合,当时间趋于无穷大时,在任何一个有界集上出 ...

  3. cocos2d-x 3.0rc2中读取sqlite文件

    cocos2d-x 3.0rc2中读取sqlite文件的方式,在Android中直接读取软件内的会失败.须要复制到可写的路径下 sqlite3* dbFile = NULL; std::string ...

  4. Tomcat不能自动编译JSP文件问题的一种解决方法

    今天碰到一个非常奇怪的问题,机器环境是JDK8.Tomcat8,把jQuery MiniUI ( for Java Eclipse)下载后导入到Eclipse中,首页可以显示,但运行操作数据库的页面出 ...

  5. android studio 翻译插件

    插件下载地址 https://github.com/Skykai521/ECTranslation/releases 使用说明: http://gold.xitu.io/entry/573d8d92a ...

  6. adding validation annotators to model classes 在linq to EntityFrame的Model中添加前台验证validation annotators

    The same solution can be applied for LINQ to SQL. The snippet the article shows for using the Metada ...

  7. 安装mmseg出错 config.status: error: cannot find input file: src/Makefile.in

    aclocallibtoolize --forceautomake --add-missingautoconfautoheadermake clean

  8. 将数据库表导入到solr索引

    将数据库表导入到solr索引 编辑solrcofnig.xml添加处理器 <requestHandler name="/dataimport" class="org ...

  9. Cubieboard2裸机开发之(一)点亮板载LED

    前言 CUbieboard2板载两个LED,一个绿色的,一个蓝色的,其中绿色LED通过三极管与PH20管脚连接,蓝色LED通过三极管与PH21管脚连接,这里只以蓝色LED为例,电路原理图如图1和图2所 ...

  10. HTML5新特性之Web Worker

    1.概述 JavaScript语言采用的是单线程模型,也就是说,所有任务排成一个队列,一次只能做一件事.随着电脑计算能力的增强,这一点带来很大的不便,无法充分发挥JavaScript的潜能.龙其考虑到 ...