Hash算法知识点总结

Hash算法
    优点
        快:search,insert,delete.O(1)
    分类
        静态hash法
            平方取中法:关键字平方值的中间某几位做为桶地址。
            折叠法:把关键字K分解成长度相等的几段,最右一段可能不相等。再把各段加起来做hash地址。
                平移折叠:各段向右对齐相加
                边界对齐折叠:把偶数段逆序后,再把所有的段相加。
            把关键字变换成整数:
                由于Hash函数本身就会把不同的关键字映射到相同的Hash地址,因此每个非数字关键字不必非要转换到不同的非负整数。
            溢出处理:
                开放地址法
                    线性探测法:发生溢出时,顺序探测表中的桶位,直到有空位为止。没有空位时,要增加表的长度。一般会设计一个阈值,如装填因子到0.75时,加表长。
                    二次探测法:上面的方法会使关键字拥挤成一团一团的,相邻的各团紧靠一起。增加了关键字的查找时间。探测桶位sqrt(i),-sqrt(i),....
                    再hash法: 一族hash函数,h1,h2,... 探测顺序是hi(k)
                链地址法:每一个桶位设一个线性表,桶位中存放指向这个线性表的指针,并用这个线性表存放所有映射到同一桶位的同义词。
            总结一点:采用余数法构造Hash函数,并选用链地址法处理溢出。一般而言都能得到最好的性能。
            无论开放地址法还是链地址法,在最差情况下,一次成功查找的比较次数都是O(n),如果换链表成平衡查找树,则为O(logn)
            余数法:h(k)=k mod D (k>=0) [0, D-1]
            对D的讨论:D不能为偶数,因为关键字可以或奇或偶,此时结果就不能消除偏向性。
            实践证明:只要D中的最小素因子不小于20,多数的关键字就可以相当均匀地被映射到所需桶号范围之内了。这只是理论,看看Java中的HashMap就知道了。
            关键字密度: 存放在hash表中的关键字/所有的关键字。
            装填因子:存放在hash表中的关键字/(桶数乘以槽数)
            同义词:不同的关键字被映射到相同的桶地址,则这些关键字叫同义词。
            溢出,冲突。
            Hash函数设计原则:便于计算,减少冲突,一致映射。
            一致映射:在关键字空间随机选取k,h应把k等概率地映射到桶号去。一致映射Hash函数。
            常用的一致映射Hash函数:算术运算(关键字是整数的直接可以运算,字符串先转变成整数再来运算。)
        动态hash法:在hash表的元素增长时,动态的调整hash桶的数目。
            作用及目的:
                当Hash表扩容后,重新映射所有的,如果数据多,而又要提供不间断服务,7x24。当hash表重构时,存取操作必须暂停,
                为了解决表扩容时可能造成的过长暂停时间,就可以用动态hash方法。
                它保证了在表重构时表中存放的所有各项数据仅涉及一桶数据改变。
            多hash表
                缺点:一存在桶满的情况下就要分配一个hash表,因此占用内存空间大,当数据较集中时,桶利用率更低。
                多个hash表共用一个hash函数,多个目录。
                详细说明可以查看:http://my.oschina.net/u/874225/blog/180266
            可扩展的动态散列(带目录的动态hash法)
                用翻倍的目录项数来取代翻倍的桶的数目,且每次只分裂有溢出的桶。
                优点:用目录项翻倍的小代价换取了桶数翻倍的大代价。
                缺点:当数据有较大的偏向性时,会使目录项的数目很大。而且增加的速度是指数级的。
                详细说明可以查看:http://my.oschina.net/u/874225/blog/180266
            线性散列(不带目录的动态hash法)
                详细说明可以查看:http://my.oschina.net/u/874225/blog/180266
                各个桶轮流进行分裂,当一轮分裂完成之后,进入下一轮分裂。level表示当前的轮数。从0开始。
                hash表初始的桶数为:N。要求N是2的幂次方。logN是指表示N个桶数需要最少几位。用d0表示。
                每一轮的初始桶数为:N*2^level。
                next指向下次将被分裂的桶。
                每次桶分裂的条件可以灵活选则。桶满or装填因子。
                每次发生分裂的桶由next指定的,与当前值被插入的桶已满或溢出无关,为了处理溢出,引入溢出页来解决。
                具体的实现可以参考java.util.HashMap的实现。
Hash算法
    缺点:数据的局部集中性(也叫偏向性)会使hash的性能急剧下降。即映射后得到同一个结果。
分类
    静态hash法
        平方取中法:关键字平方值的中间某几位做为桶地址。
        折叠法:把关键字K分解成长度相等的几段,最右一段可能不相等。再把各段加起来做hash地址。
            平移折叠:各段向右对齐相加
            边界对齐折叠:把偶数段逆序后,再把所有的段相加。
        把关键字变换成整数:
            由于Hash函数本身就会把不同的关键字映射到相同的Hash地址,因此每个非数字关键字不必非要转换到不同的非负整数。
        溢出处理:
            开放地址法
                线性探测法:发生溢出时,顺序探测表中的桶位,直到有空位为止。没有空位时,要增加表的长度。一般会设计一个阈值,如装填因子到0.75时,加表长。
                二次探测法:上面的方法会使关键字拥挤成一团一团的,相邻的各团紧靠一起。增加了关键字的查找时间。探测桶位sqrt(i),-sqrt(i),....
                再hash法: 一族hash函数,h1,h2,... 探测顺序是hi(k)
            链地址法:每一个桶位设一个线性表,桶位中存放指向这个线性表的指针,并用这个线性表存放所有映射到同一桶位的同义词。
        总结一点:采用余数法构造Hash函数,并选用链地址法处理溢出。一般而言都能得到最好的性能。
        无论开放地址法还是链地址法,在最差情况下,一次成功查找的比较次数都是O(n),如果换链表成平衡查找树,则为O(logn)
        余数法:h(k)=k mod D (k>=0) [0, D-1]
        对D的讨论:D不能为偶数,因为关键字可以或奇或偶,此时结果就不能消除偏向性。
        实践证明:只要D中的最小素因子不小于20,多数的关键字就可以相当均匀地被映射到所需桶号范围之内了。这只是理论,看看Java中的HashMap就知道了。
        关键字密度: 存放在hash表中的关键字/所有的关键字。
        装填因子:存放在hash表中的关键字/(桶数乘以槽数)
        同义词:不同的关键字被映射到相同的桶地址,则这些关键字叫同义词。
        溢出,冲突。
        Hash函数设计原则:便于计算,减少冲突,一致映射。
        一致映射:在关键字空间随机选取k,h应把k等概率地映射到桶号去。一致映射Hash函数。
        常用的一致映射Hash函数:算术运算(关键字是整数的直接可以运算,字符串先转变成整数再来运算。)
    动态hash法:在hash表的元素增长时,动态的调整hash桶的数目。
        作用及目的:
            当Hash表扩容后,重新映射所有的,如果数据多,而又要提供不间断服务,7x24。当hash表重构时,存取操作必须暂停,
            为了解决表扩容时可能造成的过长暂停时间,就可以用动态hash方法。
            它保证了在表重构时表中存放的所有各项数据仅涉及一桶数据改变。
        多hash表
            缺点:一存在桶满的情况下就要分配一个hash表,因此占用内存空间大,当数据较集中时,桶利用率更低。
            多个hash表共用一个hash函数,多个目录。
            详细说明可以查看:http://my.oschina.net/u/874225/blog/180266
        可扩展的动态散列(带目录的动态hash法)
            用翻倍的目录项数来取代翻倍的桶的数目,且每次只分裂有溢出的桶。
            优点:用目录项翻倍的小代价换取了桶数翻倍的大代价。
            缺点:当数据有较大的偏向性时,会使目录项的数目很大。而且增加的速度是指数级的。
            详细说明可以查看:http://my.oschina.net/u/874225/blog/180266
        线性散列(不带目录的动态hash法)
            详细说明可以查看:http://my.oschina.net/u/874225/blog/180266
            各个桶轮流进行分裂,当一轮分裂完成之后,进入下一轮分裂。level表示当前的轮数。从0开始。
            hash表初始的桶数为:N。要求N是2的幂次方。logN是指表示N个桶数需要最少几位。用d0表示。
            每一轮的初始桶数为:N*2^level。
            next指向下次将被分裂的桶。
            每次桶分裂的条件可以灵活选则。桶满or装填因子。
            每次发生分裂的桶由next指定的,与当前值被插入的桶已满或溢出无关,为了处理溢出,引入溢出页来解决。
            具体的实现可以参考java.util.HashMap的实现。
优点
    快:search,insert,delete.O(1)
缺点:数据的局部集中性(也叫偏向性)会使hash的性能急剧下降。即映射后得到同一个结果。

你可能感兴趣的:(Hash算法知识点总结)