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

时间:2022-08-28 19:24:18

/*-----------------------------------------------------------------------------
**   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&period;C

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

  2. EPANET中读取INPUT文件的函数文件——INPUT1&period;C&sol;INPUT2&period;C&sol;INPUT3&period;C

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

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

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

  4. 哈希表&lpar;Hash&rpar;的应用

    $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. 词典&lpar;二&rpar; 哈希表&lpar;Hash table&rpar;

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

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

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

  9. Python 中的哈希表

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

随机推荐

  1. android MVC &amp&semi;&amp&semi; MVP &amp&semi;&amp&semi; MVVM分析和对比

    相关:http://www.cnblogs.com/wytiger/p/5305087.html 出处http://blog.csdn.net/self_study,对技术感兴趣的同鞋加群544645 ...

  2. Java基础-重写System&period;out&period;println方法

    PrintStream myStream = new PrintStream(System.out) { @Override public void println(String x) { super ...

  3. &lbrack;bzoj2118&rsqb;墨墨的等式【dijk&plus;堆】

    10/30的update:如果是冲着dijk的板子来的,建议看多校联考contest中第二场day2的T2,那边的写法比较优秀... --------------------------------- ...

  4. Android如何获取开机启动项列表

    static final String BOOT_START_PERMISSION = "android.permission.RECEIVE_BOOT_COMPLETED"; p ...

  5. druid简单教程

    java程序很大一部分要操作数据库,为了提高性能操作数据库的时候,有不得不使用数据库连接池.数据库连接池有很多选择,c3p.dhcp.proxool等,druid作为一名后起之秀,凭借其出色的性能,也 ...

  6. 设置Proxy Server和SQL Server实现互联网上的数据库安全

    ◆首先,我们需要了解一下SQL Server在WinSock上定义协议的步骤: 1. 在”启动”菜单上,指向”程序/Microsoft Proxy Server”,然后点击”Microsoft Man ...

  7. Android Activity的任务栈和四大启动模式

    在安卓系统中默认每次启动一个Activity时,系统会创建一个实例,并按照先进后出的原则放入任务栈中,当我们按back键时,就会有一个activity从任务栈顶移除,重复下去,直到任务栈为空,系统就会 ...

  8. 安卓开发笔记(三十一):shape标签下子类根结点的具体使用

    在我的上一篇博文当中阐述了我们如何使用shape标签进行自定义控件,这里对shape控件的属性进行阐述,不知道如何使用这些属性的可以参见我的上一篇博文(自定义Button):https://www.c ...

  9. LabVIEW(九):程序结构中的分支结构和顺序结构

    一.分支结构 1.创建分支结构:程序框图右键>结构>条件结构 2.Ctrl + I 会显示错误列表,双击错误列表会定位到该错误在程序框图中地方. 3.有的分支可以不连接分支内容. 在不连接 ...

  10. 无法打开运行空间池,服务器管理器winrm插件可能已损坏或丢失

    在使用windows2012 的服务器或云主机时,服务器安装不了iis服务. 提示 “无法打开运行空间池,服务器管理器winrm插件可能已损坏或丢失”. 这个问题可能的原因是您的机器未设置虚拟内存,可 ...