注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

水中央

独自盼望

 
 
 

日志

 
 

HASH函数日志(转载)  

2008-12-02 10:34:15|  分类: 工作学习 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Hash函数是一种映射关系,通过一种映射关系,将原本的字符串,数字或其他关键信息转换为一个索引值。

用数学关系式表示为:

   index  =  function(key)

数序上有不同的映射关系,不同的key,有可能会获取相同的index,这个时候的index就是有重码,也就是collosion,这就导致了Hash函数的不唯一性,从而在查找index下的关键字时也是有冲突的。

目前一些常用的数学映射关系为:

   1、直接定址法,就是直接使用key作为index

   2、数字分析法,取key中的若干位数作为index,有较多冲突

   3、平法取中法,取key的平方,然后取中间几位作为index(index与key值密切相关),

   4、折叠法,将key从中间分割成几个部分,然后按照一定规则相加获取的结果为index。

   5、除留余数法,将key对某个数值m求余,获取的余数即为index,显然indxe<m,也就是如果key>m,必然会有n-m个冲突存在(n为key关键字的个数)。

   6、随机数法,将key值通过随机数求取index,即function(key)=random(key),伪随机数的均匀性较好,当关键字长度不相等时,用此法构造较为恰当。

解决冲突:

    其实并不是将冲突去掉,而是通过一种变通的方法,将冲突变得可以唯一查找,而不是有冲突就没有唯一的index位置了。

   解决方法有:

    一、开放定址法:

             index = (function(key)+di)mod m

               di:增长序列,m哈希表长,d的求取方法有下面集中。

      1、线性探测再散列,就是查找或插入时,如果发生冲突,就线性排列下去,下面还有冲突,继续排列下去,直到没有冲突时,查找结束或添加index。d=1,2,3,……,m-1

     2、二次探测再散列,d=1^2,-1^2,2^2,-2^2,……,±k^2(k<=m/2)

     3、伪随机探测再散列,d=random(key)

  二、再Hash法

        即将index冲突的key关键字进行另一种Hash算法,得到key关键的index2索引值,从而来降低和避免冲突,当然要将冲突完全避免,则需要多个Hash算法隐含在其中。

 三、链地址法

        当Index发生冲突时,将同一个index下冲突的key值都放在以index开头的链表中,这样index开头的链表中的key都可以比较方便的查找出来。

四、建立溢出表

         建立一个和key关键字一样多的index索引,当index发生冲突时,将所有发生冲突的key或index都放在溢出表中。

Hash表查找:

  

HASH函数日志(转载) - 天字2号 - 水中央// -------开放定址Hash表的存储结构------------

HASH函数日志(转载) - 天字2号 - 水中央HASH函数日志(转载) - 天字2号 - 水中央int hashsize[]=...{997,...};  //Hash表容量递增表,一个合适的素数序列

HASH函数日志(转载) - 天字2号 - 水中央HASH函数日志(转载) - 天字2号 - 水中央typedef struct...{

HASH函数日志(转载) - 天字2号 - 水中央   ElemType *elem;           //数据元素存储基址,动态分配数组

HASH函数日志(转载) - 天字2号 - 水中央   int              count;          // 当前数据元素的个数

HASH函数日志(转载) - 天字2号 - 水中央   int              sizeIndex;   //hashsize[sizeIndex]为当前容量

HASH函数日志(转载) - 天字2号 - 水中央}HashTable;

//--------链接地址Hash表的存储结构---------------

typedef struct childchain

{

   ElemType data;   // 数据值

   struct childchain *next;  // 下一个childchain值,NULL结束

}ChildChainHash

  typedef struct mainchain{

    int index;   // 主链的索引值

    ChildChainHash  *child;  // 指向冲突的child子链,当没有冲突时,给予NULL值。

   struct mainchain *main;  //

}MainChainHash;

HASH函数日志(转载) - 天字2号 - 水中央

HASH函数日志(转载) - 天字2号 - 水中央#define SUCCESS 1

HASH函数日志(转载) - 天字2号 - 水中央#define UNSUCCESS 0

HASH函数日志(转载) - 天字2号 - 水中央#define DUPLICATE -1

采用链接构建Hash的思路,MainChainHash申请一个head指针和若干个变量,然后main指针依次指向下一个MainChainHash指针,而每一个child指针,指向ChildChainHash链中的值,这样一个Hash表就 构造完成了。当主键key使用Hash一下获取的Index时,通过Index索引值知道Child链,从而构造了一个核实的Hash表。

HASH函数日志(转载) - 天字2号 - 水中央// 采用开放式哈希表的存储结构

HASH函数日志(转载) - 天字2号 - 水中央

HASH函数日志(转载) - 天字2号 - 水中央Status SearchHash(HashTable H, KeyType k, int &p, int &c)

HASH函数日志(转载) - 天字2号 - 水中央HASH函数日志(转载) - 天字2号 - 水中央...{

HASH函数日志(转载) - 天字2号 - 水中央     // 开放地址哈希表H中查找关键字k的元素,若查找成功,以p指示待查数据,

HASH函数日志(转载) - 天字2号 - 水中央   // 元素在表中位置,并返回SUCESS,否则,以p指示插入位置,并返回UNSUCESS,

HASH函数日志(转载) - 天字2号 - 水中央   // c用以计冲突次数,其初值置零,供建表插入时参考

HASH函数日志(转载) - 天字2号 - 水中央  p  = Hash(k);   // 求得hash地址表

HASH函数日志(转载) - 天字2号 - 水中央  while( H.elem[p].key != NULLKEY &&   //该位置中填有记录

HASH函数日志(转载) - 天字2号 - 水中央           !EQ( k,H.elem[p].key)                 // 并且关键字不相等

HASH函数日志(转载) - 天字2号 - 水中央          collision( p, ++c) ;                  // 求得下一探索地址p

HASH函数日志(转载) - 天字2号 - 水中央   if (EQ(K, H.elem[p].key ) )

HASH函数日志(转载) - 天字2号 - 水中央          return SUCCESS;                 // 查找成功,p返回待查数据元素位置

HASH函数日志(转载) - 天字2号 - 水中央   else

HASH函数日志(转载) - 天字2号 - 水中央         return UNSUCESS;              // 查找不成功.( H.elem[p].key == NULLKEY )

HASH函数日志(转载) - 天字2号 - 水中央                                                      // p返回的是插入的位置

HASH函数日志(转载) - 天字2号 - 水中央}// SearchHash

HASH函数日志(转载) - 天字2号 - 水中央

HASH函数日志(转载) - 天字2号 - 水中央Status InsertHash( HashTable &H, ElemType e)

HASH函数日志(转载) - 天字2号 - 水中央HASH函数日志(转载) - 天字2号 - 水中央...{

HASH函数日志(转载) - 天字2号 - 水中央     // 查找不成功时,插入数据元素e到开放定址Hash表H中,并返回OK,

HASH函数日志(转载) - 天字2号 - 水中央    // 若冲突次数过大,需重新构建Hash表

HASH函数日志(转载) - 天字2号 - 水中央   c = 0;

HASH函数日志(转载) - 天字2号 - 水中央   if( SearchHash( H,e.key,p,c ))

HASH函数日志(转载) - 天字2号 - 水中央        return DUPLICATE;           // 表中已有与e有相同关键字的元素

HASH函数日志(转载) - 天字2号 - 水中央  else if ( c <hashsize[H.sizeindex]/2 )  //冲突次数c未达到上限时,(c的阈值可调)

HASH函数日志(转载) - 天字2号 - 水中央HASH函数日志(转载) - 天字2号 - 水中央  ...{

HASH函数日志(转载) - 天字2号 - 水中央         H.elem[p] = e; ++H.count; return OK;    // 插入e

HASH函数日志(转载) - 天字2号 - 水中央   }

HASH函数日志(转载) - 天字2号 - 水中央   else 

HASH函数日志(转载) - 天字2号 - 水中央HASH函数日志(转载) - 天字2号 - 水中央  ...{

HASH函数日志(转载) - 天字2号 - 水中央     RecreateHashTable(H);

HASH函数日志(转载) - 天字2号 - 水中央    return UNSUCESS;    // 重建hash表

HASH函数日志(转载) - 天字2号 - 水中央  }

HASH函数日志(转载) - 天字2号 - 水中央}  // InsertHash

摘抄自严蔚敏的C数据结构中Hash章节。

Hash表最大的特点:

    不管n有多大,即表有多长,我们总可以选择一个合适的装填因子以便将来平均查找长度限定在一个范围之内。

查找长度

链地址:

          S=1+α /2

线性探测:

          S = 1/2 (1+1/(1-α ) )

伪随机探测:

          S = -1/α ln(1-α )

  评论这张
 
阅读(27)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017