Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

README.md

散列表 HashTable

散列表(hash table 哈希表),是根据关键码值(key value)而直接进行访问的数据结构.如python的dict类,C#的Dictionary类,C++的map类,java的HashTable类

通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度

这个函数叫做散列函数,存放记录的数组叫散列表

ELF Hash

def ELFhash(self, key : str, mod):
        h = 0
        for c in key:
            h = (h << 4) + ord(c)
            g = h & 0xF0000000
            if g != 0:
                h ^= g >> 24;
            h &= ~g;  
        return h // mod  

哈希和哈希表

哈希表是一个通过哈希函数来计算数据存储位置的数据结构,通过支持如下操作:

  • Insert(key, value):插入键值对(key, value)
  • Get(key):如果存在键为key的键值对,则返回其value,否则返回null
  • delete(key):删除键为key的键值对

哈希表的优势:高效,读写操作甚至可以做到O(1)的时间复杂度

直接寻址缺点

  • 无法处理关键字不是数字的情况

  • 当域U很大时,对于有限的内存,存储大小为|U|的一张表T很不实际

  • 若关键字集合T相对于U很小,分配给T的大部分空间都要浪费掉

解决方案为使用哈希函数h,根据关键字k计算出槽的位置.函数h将关键字域U映射到哈希表T[0..m-1]的槽位上

  • IPv4的格式:A.B.C.D 其中ABCD分别是一个0到255的整数,例如127.0.0.1,哈希函数H的设计要求。将其看做256进制的4位数,H(A.B.C.D)=256^3A + 256^2B + 256C + D

常用哈希法

  • 除法哈希法 h(k) = k mod m k为关键字,m为槽的大小

  • 乘法哈希法 h(k) = [m (kA mod 1)] 1.用关键字k乘上常数A(0<A<1),并抽取出kA的小数部分;2.用m乘以这个值,再取结果的底。哈希函数如下:h(k)

哈希冲突/碰撞

  • 哈希冲突后,位于同一个槽的元素按链表放置,目前主流语言处理都是当链表元素超过8个以后,将链表换为平衡二叉查找树(红黑树)处理,减小搜索时间

  • 开放寻址法:所有元素都放在哈希表里面,或包含NIL,使用探查的方式,连续的检查哈希表,直到找到一个空槽来放置,不使用链表或者其他数据结构

  • 线性探查使用的哈希函数: h(k,i)=(h`(k) + i) mod m,i=0,1,...,m-1

  • 开放寻址法的缺点:从哈希表中删除操作元素比较困难。不能仅将NIL置于其中来标识它为空。有一个解决办法,就是在槽i中放置一个特定的值DELETED替代NIL来标记该槽

  • 线性探查的分析:优点:容易实现,Cache友好,装载因子可以接近1;缺点:很多哈希值近似的元素会聚集在一起

  • 二次探查使用的哈希函数: h(k,i)=(h`(k) + c1 * i + c2 * i^2) mod m,i=0,1,...,m-1

没有线性探查很多哈希值相似就集中在一起的情况

为了充分利用哈希表,c1,c2和m的值要受到限制

Cache不友好,多个相同哈希值相同的元素会聚集在一起

装填因子

装填因子等于已插入的键值对数目除以总的容量,装填因子越高,空间利用率越高,但是冲突的可能性会增高,降低访问效率

一个好的哈希策略应该让装填因子尽可能高,同时访问效率尽可能高

理想情况设装填因子为a,假设插入的键值的哈希值随机且独立,所有插入的键值在哈希表中的位置完全随机,从任意一点开始看,从它开始的槽连续不为空的长度期望值为∑ia^i(1-a),假设N足够大,求和约等于a/(1-a)

  • 线性探查中,成功的搜索的期望探查长度为: 0.5(1 + 1 / (1- a)),不成功的搜索和插入新键值的期望探查长度为:0.5(1+1/(1-a)^2)

双重哈希

双重哈希是用于开放寻址法的最好的方法之一,因为它所产生的排列具有随机选择排列的许多特性 h(k, i) = (h1(k) + ih2(k)) mod m

双重哈希的装填因子为a,假设插入key的哈希值随机且独立,不成功的搜索的期望探查长度为1/(1-a),成功的搜索的期望探查长度为1/aln(1/(1-a))

链表法和开放寻址法的比较

优点:实现简单,缺点:对Cache不友好,出现聚集的现象时效率低,特别的,开放寻址法处理删除比较困难

布谷鸟哈希

两个哈希函数h1和h2,一个元素k在哈希表中的位置或者为h1(k)或者h2(k)

  • 查找: 分别查看h1(k)和h2(k)即可
  • 删除:首先查找,若k存在,则直接将其删除即可
  • 插入:相当于一个长度为2的队列,

优点:查找和删除最坏情况下只需要访问两个位置

跳房子哈希

一个元素k在哈希表中的位置或者为h(k),或者为h(k)的L个邻居之一

优点达到很高的装填因子,提高空间利用率,缺点,查找和删除最坏复杂度是O(L),局部性很好,这一点对于外村哈希表特别重要

哈希表缺点

  • 每个操作执行一次或多次哈希计算
  • 不支持范围查询
  • 哈希表的大小固定,计算开销大,但是平摊复杂度仍为常数

哈希分片

key-partition-matchine-value

范围分片

  • RoundRobin

H(key) = hash(key) mod k

缺乏扩展性

  • 虚拟桶

单层桶变为两层映射,扩展性强

  • 一致性哈希

分布式哈希表(DHT),是P2P网络和分布式存储中常见的一项技术

将哈希数据空间按照大小组成首尾相接的环状序列

路由问题:

MD5算法

数据映射为128位的哈希串,文件校验

SHA-2

SHA-224 SHA-256 SHA-384 SHA-512