zoukankan      html  css  js  c++  java
  • 哈希表及哈希表查找相关概念(转)

    1. 哈希表的概念
       对于动态查找表而言,1) 表长不确定;2)在设计查找表时,只知道关键字所属范围,而不知道确切的关键字。因此,一般情况需建立一个函数关系,以f(key)作为关键字为key的录在表中的位置,通常称这个函数f(key)为哈希函数。(注意:这个函数并不一定是数学函数)

     1. 哈希函数是一个映象,即:将关键字的集合映射到某个地址集合上,它的设置很灵活,只要这个地址集合的大小不超出允许范围即可;
     2. 由于哈希函数是一个压缩映象,因此,在一般情况下,很容易产生“冲突”现象,即:key1 key2,而 f(key1) = f(key2) 并且,改进哈希函数只能减少冲突,而不能避免冲突。
          因此,在设计哈希函数时,一方面要考虑选择一个“好”的哈希函数;另一方面要选择一种处理冲突的方法。所谓“好”的哈希函数,指的是对于集合中的任意一个关键字,经哈希函数“映象”到地址集合中任何一个地址的概率是相同的,称这类哈希函数为“均匀的”哈希函数。
      根据设定的哈希函数H(key)和所选中的处理冲突的方法,将一组关键字映象到一个有限的地址连续的地址集(区间)上,并以关键字在地址集中的“象”作为相应记录在表中的存储位置,这种表被称为哈希表。哈希表是基于哈希函数建立的一种查找表。

    2. 哈希函数的构造方法

      对数字的关键字可有下列哈希函数的构造方法,若是非数字关键字,则需先对其进行数字化处理。
    (1) 直接定址法
      哈希函数为关键字的线性函数:
       H(key) = key 或者 H(key) = a key + b
      适用场合:地址集合的大小 = 关键字集合的大小 
    (2)数字分析法
      假设关键字集合中的每个关键字都是由s位数字组成(k1, k2, …, kn),分析关键字集中的
      全体,并从中提取分布均匀的若干位或它们的组合作为地址。
      适用场合:能预先估计出全体关键字的每一位上各种数字出现的频度。
    (3) 平方取中法
      若关键字的每一位都有某些数字重复出现频度很高的现象,则先求关键字的平方值,以通过
      “平方”扩大差别,同时平方值的中间几位受到整个关键字中各位的影响;
    (4) 折叠法
      若关键字的位数特别多,则可将其分割成几部分,然后取它们的叠加和为哈希地址。可有
      
    移位叠加间界叠加两种处理方法。
    (5) 除留余数法
       H(key) = key MOD p p≤m (表长)
      关键问题是:如何选取 p ?
      p 应为不大于m 的质数或是不含20以下的质因子
      例如:key = 12, 39, 18, 24, 33, 21 时, 若取 p=9, 则使所有含质因子3的关键字均映射
         到地址0, 3, 6 上,从而增加了“冲突”的可能性。
    (6) 随机数法
      H(key) = Random(key)实际造表时,采用何种构造哈希函数的方法取决于建表的关键字集合
       的情况(包括关键字的范围和形态),总的原则是使产生冲突的可能性降到尽可能地小。

    3. 处理冲突的方法
      处理冲突的实际含义是:为产生冲突的地址寻找下一个哈希地址。
    (1)开放定址法
      为产生冲突的地址H(key)求得一个地址序列:
      H0, H1, H2, …, Hs 1≤s≤m-1
      其中:H0 = H(key)
      Hi = ( H(key) + di ) MOD m i=1, 2, …,s
      增量 di 有三种取法:
      1) 线性探测再散列
       di = c i 最简单的情况 c=1
      2) 平方探测再散列
       di = 1², -1², 2², -2², …,
      3) 随机探测再散列
       di 是一组伪随机数列
       注意:增量di应具有“完备性”,即产生的Hi均不相同,且所产生的s(m-1)个Hi值能覆盖
           哈希表中所有的地址。要求:
       · 平方探测时的表长m必为4j+3的质数;
       · 随机探测时的m和di没有公因子。
    (2)链地址法
       将所有哈希地址相同的记录都链接在同一链表中。
       线性探测容易产生二次聚集,链地址肯定不会产生二次聚集。一次聚集的产生主要取决于哈希函数,在哈希函数均匀的前提下,可以认为没有一次聚集。 

    (3)再哈希法

            在同义词产生地址冲突时计算另一个哈希函数地址,直到冲突不再发生。这种方法不易产生“聚集”,但增加了计算时间。

    4. 哈希表的查找

      查找过程和造表过程一致。假设采用开放定址处理冲突,则查找过程为:
      对于给定值K, 计算哈希地址 i = H(K) ,若r[i] = NULL 则查找不成功;
      若 r[i].key = K 则查找成功, 否则求下一地址Hi,直至r[Hi] = NULL (查找不成功)
      或r[Hi].key = K (查找成功)为止。
     
    //--- 开放定址哈希表的存储结构 ---

    int hashsize[] = { 997, ... }; // 哈希表容量递增表,一个合适的素数序列
    typedef struct {
         ElemType *elem; // 数据元素存储基址, 动态分配数组
         int count; // 当前数据元素个数
         int sizeindex; // hashsize[sizeindex]为当前容量
    } HashTable;
    
    
    #define SUCCESS 1
    #define UNSUCCESS 0
    #define DUPLICATE -1 
    
    
    Status SearchHash (HashTable H, KeyType K, int &p, int &c) {
    // 在开放定址哈希表H中查找关键码为K的元素,若查找成功,以p指示待查数据元素在表中位置,并返回SUCCESS;否则,以p指示插入位置,并返回UNSUCCESS, c用以计冲突次数,其初值置零,供建表插入时参考
      p = Hash(K); // 求得哈希地址
      while ( H.elem[p].key != NULLKEY && !EQ(K, H.elem[p].key)) 
    // 该位置中填有记录并且关键字不相等
      collision(p, ++c); // 求得下一探查地址p
      if (EQ(K, H.elem[p].key)) 
        return SUCCESS; // 查找成功,p返回待查数据元素位置
      else return UNSUCCESS;// 查找不成功,p返回的是插入位置
    } // SearchHash
    

     
    通过调用查找算法实现了开放定址哈希表的插入操作。

    Status InsertHash (HashTable &H, Elemtype e) {
    // 查找不成功时插入数据元素e到开放定址哈希表H中,并返回OK;若冲突次数过大,则//重建哈希表
      c = 0;
      if ( HashSearch ( H, e.key, p, c ) == SUCCESS )
        return DUPLICATE; // 表中已有与e有相同关键字的元素
      else if ( c < hashsize[H.sizeindex]/2 ) { // 冲突次数c未达到上限,(阀值c可调)
        H.elem[p] = e; ++H.count; return OK; // 插入e
         } 
    else RecreateHashTable(H); // 重建哈希表
    } // InsertHash
    

    可见,无论查找成功与否,ASL均不为零。

    决定哈希表查找的ASL的因素:
    1. 选用的哈希函数;
    2. 选用的处理冲突的方法;
    3. 哈希表饱和的程度,装载因子α=n/m 值的大小一般情况下,可以认为选用的哈希函数是“均匀”的,则在讨论ASL时,可以不考虑它的因素。哈希表的ASL是处理冲突方法和装载因子的函数。可以证明查找成功时有下列结果:


     
     
    5. 哈希表的删除操作
      从哈希表中删除记录时,要作特殊处理,相应地要修改查找算法对静态查找表,有时也可能找到不发生冲突的哈希函数。 即此时的哈希表的ASL=0, 此类哈希函数为理想(perfect)的哈希函数

    努力奋斗的小墨鱼 ---- http://www.cnblogs.com/WayneZeng/
  • 相关阅读:
    linux下的第一个C程序及其编译方法
    使用open_read_write等底层函数来赋值一个文件
    C++中预定义的宏
    altibase MDB的创建sequence的举例
    C中的时间函数的用法
    联系表单 1
    《jQuery基础教程》读书笔记
    《jQuery基础教程》读书笔记
    《jQuery基础教程》读书笔记
    『原创·翻译』如何阅读论文
  • 原文地址:https://www.cnblogs.com/WayneZeng/p/2725916.html
Copyright © 2011-2022 走看看