哈希算法原理

哈希原理 及 uthash 源码分析
  1. 应用背景
    众所周知,数组的特点是,可以随机访问,即寻址容易,但插入和删除困难;
    链表的特点是,不支持随机访问,即寻址困难,但插入和删除容易;
    哈希结构是为了综合数组和链表的特性,而设计产生的一种数据结构,即它同时满足寻址容易,和方便插入和删除的特性;

  2. 哈希原理
    哈希表(或称散列表)引入的时是一种最有效的检索方法:散列方法。从本质上来讲哈希表是一个数组,通过特殊的索引值来
    访问数组中的元素,它以关键字值为输入,通过散列函数来计算该关键字值所对应的元素在哈希表中的存储单元的地址,进而实现
    快速访问元素。如下所示:
    散列函数(hash 函数) : f(关键字值K) ----------> 散列表中的以K为关键字的元素的存储地址

    如上,哈希函数的输入是–关键字值,输出是–关键字值对应的元素的存储单元的地址,从而,在散列表中可以直接访问相
    应的元素,因此哈希表最大的特点是,通过哈希函数的计算和数组中的索引都只消耗常量固定的时间,来实现快速访问元素的目的。

    散列方法的核心是散列函数及冲突消解方法:
    为了获得一个好的函数,通常应使函数f与组成关键字K的所有符号有关,若K是从关键字集合中随机选取的一个,则希望f(K)
    以等概率取区间[0,M-1]中的每一个值,满足此性质的散列函数称为是均匀的,有实验证明,有两大类散列函数相当好,一类是以
    出除法基础的,另一类是以乘法为基础的
    哈希函数在通过关键字值计算哈希编码时,有可能产生两个不同的关键字值计算出来的哈希编码是相同的情形,此时就产生了
    冲突,好的哈希函数能最大限度的减少冲突,但冲突不可能完全消除,解决冲突也成为溢出处理技术,常见的解决冲突的方法有:
    拉链法和开地址法。

  3. 常用的哈希方法
    常见的哈希方法有:拉链法 和 开地址法 。
    (1). 拉链法
    为哈希函数的值域 [0,M-1] 中的每一个值维护一个链而不是一个节点,从而可以使某个散列地址可以被多个关键值
    所共享,即每一个链中存着一组其关键字互相冲突的元素,每个链表都可以看做时一个桶,插入元素时,通过哈希函数首先
    计算出元素属于那个桶,然后在相应的链表头插入元素,查找或删除元素时同样先确定是哪个桶,然后遍历相应的桶,直到
    发现要找的元素。每个桶都是一个链表,它并不限制包含元素的个数,但若是变的较大,性能会降低。则对有N个元素M个值
    的的哈希表,每个链的平均长度时N/M,则散列技术比使用顺序检索所花费的时间缩短了M-1倍。
    此外对于元素数目很少的时候,为了节省空间,可以改进拉链技术,方法是为值域中的每个值维护的时一个带额外指
    针的节点,而不是一个链。该链用来指向当该值冲突时,下一个关键字对应的元素在哈希表中应该存放的位置,该位置是从
    哈希表尾部逆序向上查找到的第一个空值域节点。这样便只对M个元素和M个连接(指针)提供存储空间,而不是对N个元素
    的M+N个连接提供存储空间。而且改进后,元素一旦插入表中,之后不需要移动他们。( 但限制是,N

    (2). 开地址法
    该方法不需要建立链表,假设散列表的长度为M,从空表开始,通过逐个向表中插入新元素来建立列表,插入关键值为K
    的元素的方法是,按照某种规定的次序探查允许插入新元素的空位置,地址 f(K) 称为基地址。如果f(K)已经被占用,解
    决冲突的方法是,按照某种次序检索表中的项目,直到找到一个关键字等于给定的K或者找到一个空缺位置,将该元素插入。
    线性探查法,是将冲突时的探查序列依次向下,若直至末尾还未找到空缺则循环至表开头继续向下探查。
    线性探查法的缺点是有可能使很多元素连成一片产生“聚集”现象,改进的方法是当冲突时采用伪随机发生器,来计算下
    一个探查的位置,伪随机发生器可以采用简单的函数来实现。
    此外,为了消除线性探查法带来的“聚集”现象,改进的线性探查算法还有如二次探查,双重散列法等等哈希方法。其
    原理是利用乘法散列来打碎除法散列引入的群集现象。

你可能感兴趣的:(数据结构)