- 浏览: 149195 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
EclipseEye:
fair_jm 写道不错 蛮详细的 谢谢分享
SWT/JFace专题 --- SWT中Display和多线程 -
fair_jm:
不错 蛮详细的 谢谢分享
SWT/JFace专题 --- SWT中Display和多线程
----------------hash的基本概念------------
哈希方法在“键-值对”的存储位置与它的键之间建立一个确定的对应函数关系hash(),使得每一个键与结构中的一个唯一的存储位置相对于:存储位置=hash(键)
在搜索时,首先对键进行hash运算,把求得的值当做“键-值对”的存储位置,在结构中按照此位置取“键-值对”进行比较,若键相等,则搜索成功。
在存储“键-值对”的时候,依照相同的hash函数计算存储位置,并按此位置存放,这种方法叫做哈希方法(也叫做散列方法)。在哈希方法中使用的转换函数 hash被称为 哈希函数(或散列函数)。按照此算法构造出来的表叫做哈希表(或者散列表)。
哈希函数建立了从“键-值对”到哈希表地址集合的一个映射。使用这种方法由于不必进行多次键的比较,所以搜索速度非常快。
-----
哈希 就是以空间换时间(因为hash表也需要存储空间),不过,采用哈希函数的作用之一就是减少需要被处理的数组大小,(和直接寻址相比)存储空间的开销也相应减少。
---------------hash函数------------------
通常键的取值范围比哈希表地址集合大太多,因此有可能经过同一哈希函数的计算,把不同的键映射到了同一个地址上面,这就产生了冲突。
如果“键-值对”在加入哈希表的时候产生了冲突,就必须找另外一个地方来存储它,冲突太多会降低数据插入和查找的效率,因此希望找到一个不容易产生冲突的函数,即构造一个地址分布比较均匀的哈希函数。
常用的hash函数包括:
直接定址法(用于key值为数字或有一定次序规则的情况)、
数字分析法(对key中的数字规则进行分析)、
乘法散列法 将关键字key乘以一个常量A(0<A<1),并且提出key*A的小数部分;然后将这个值乘以m:
h(key)=m*(key*A-(int)(key*A))
乘法散列的一个优势是对m的值没有特别的要求,对应m,一般指定为2的幂。因为这样容易在计算机中实现哈希函数的计算。对常量A,更好的选择是依赖于被散列的数据特征,一般用A等于黄金分割点0.618033.
陈留余数法(%取余法h(key)=key%m,)
其关键是m 的选取,一般选m 为小于某个区域长度n 的最大素数,一般地说,如果 m 的约数越多,那么冲突的几率就越大
简单的证明:假设m 是一个有较多约数的数,同时在数据中存在key 满足最大公约数gcd(m,key)=d >1 ,即 有m=a*d,key=b*d,则有以下等式:key% m= key – m*[key/m] =key – m*[b/a] 。其中,[b / a]的取值范围是不会超过[0,a-1]的正整数。也就是说,[b / a]的值只有a 种可能,而m 是一个预先确定的数。因此上式的值就只有a 种可能了(这显然缩小了余数分布的范围)。这样,取mod 运算之后的余数仍然在[0,m-1]内,但是它的取值仅限于等式可能取到的那些值。也就是说余数的分布变得不均匀了。容易看出,m 的约数越多,发生这种余数分布不均匀的情况就越频繁,冲突的几率越高。而素数的约数是最少的,因此我们选用大素数。所以“m应该最优选择素数”。
平方散列法 由于%包含了*和/的操作,而乘法的运算比除法省时,可以考虑把%变为乘和移位的组合操作对应平方散列法:
可以形如:index=(key*key)>>28
对与平方散列法其实有种改进,通过实验证明这种改进是有效的就是把key*key换成key*一个常数Q,这个常数就来自于斐波那契数列中的值,对于16位整数,Q为40503;32位整数,Q为2654435769;64位整数,Q为11400714819323198485
于是对于常见在32位整数来说,index=(key*2654435769)>>28
平方取中法(key平方后取中间的几位为hash地址)、
折叠法(将key分割成几个部分,叠加求和)、
随机数法(选择一个随机函数,取关键字的随机函数值为它的哈希地址)。
应该根据实际工作中关键码的特点选用适当的方法。
----------------hash冲突---------------
为了避免冲突,选择哈希函数h()的主导思想是使h(k)的出现是“随机”的,即每个关键字都可能散列到任一个地址中去,从而减少冲突的次数。虽然采用合适的哈希方法能够降低冲突的概率,但是冲突仍然是不可避免的:
解决冲突的方法:
(1).链地址法:将具有同一散列地址的记录存储在一条线性链表中。
(2).开放地址法:如果h(k)被占用,就按照如下序列探测:(h(k)+p(1))%TSize,(h(k)+p(2))%TSize,...,(h(k)+p(i))%TSize,...
其中,h(k)为哈希函数,TSize为哈希表的长度,p(i)为探测函数。在(h(k)+p(i))%TSize的基础上,若发现冲突,则使用
增量p(i+1)进行新的探测,直到无冲突为止。
其中,根据探测函数p(i)的不同,开发地址发又分为:
线性探测法(p(i)=i:1,2,3,4,5,6,....);
二次(或平方)探测法:(p(i)=((-1)^(i-1))(i)^2:1,-1,4,-4,9,-9,......)
随机探测法(p(i):为随机数)
双散列函数(双散列函数h(key)、hp(key),如果h(key)出现冲突,则再使用hp(key)求取散列地址)
探测序列为:h(k),h(k)+hp(k), ... ,h(k)+i*hp(k),...
(3). 桶地址法
桶--一片较大的存储空间
“桶”算法:假设哈希表有m个地址,就将其改为m个“桶”,其桶号和哈希地址一一对应,每个桶用来存放互为同义词的键,也就是如果两个不同的键用哈虚函数计算得到了同一个哈希地址,就将它们放到同一个桶中,检索的时候就在桶中进行顺序检索,如果当桶满时可以用开放地址法处理。
-----
当某个bucket中存放的数据非常多时,也就是哈希表中的某个bucket冲突数据非常多时,采用哈希AVL树方式存放这些冲突数据对查找效率会有明显的提高。
-----------------解决分布式缓存的consistent hashing算法-----------------
consistent hashing算法:是一种hash算法,简单地说,在移除/添加一个cache(缓存)时,它能够尽可能小的改变已存在key映射关系,尽可能满足单调性(单调性是指:如果已经有一些内容通过哈希分配到了相应的缓存中,又有新的缓存加入到系统中。哈希的结果应该能够波安装原有已分配的内容可以被映射到新的缓存中去,而不会被映射到久的缓存集合中的其他缓冲区)的要求。
----------扩展 d-left-hashing------------
d-left-hashing,是对传统hash方法的优化和改进,以达到key位置的负载均衡。
其大概思想就是:整个哈希表被分成d个从左到右依次相邻子表,同时有d个相互独立的hash函数,当有key需要hash时,这d个hash函数同时计算,产生d个独立index,然后将key加入到负载最轻的位置中,如果负载最轻的位置有多个(比如同时为空或同时有n个),就把index指定为最左边负载最轻的子表中。
---------------
hash 在对海量数据的处理和密码学方面(如MD5算法)都有很好的应用。
------
后继还会对Hash进一步探索
哈希方法在“键-值对”的存储位置与它的键之间建立一个确定的对应函数关系hash(),使得每一个键与结构中的一个唯一的存储位置相对于:存储位置=hash(键)
在搜索时,首先对键进行hash运算,把求得的值当做“键-值对”的存储位置,在结构中按照此位置取“键-值对”进行比较,若键相等,则搜索成功。
在存储“键-值对”的时候,依照相同的hash函数计算存储位置,并按此位置存放,这种方法叫做哈希方法(也叫做散列方法)。在哈希方法中使用的转换函数 hash被称为 哈希函数(或散列函数)。按照此算法构造出来的表叫做哈希表(或者散列表)。
哈希函数建立了从“键-值对”到哈希表地址集合的一个映射。使用这种方法由于不必进行多次键的比较,所以搜索速度非常快。
-----
哈希 就是以空间换时间(因为hash表也需要存储空间),不过,采用哈希函数的作用之一就是减少需要被处理的数组大小,(和直接寻址相比)存储空间的开销也相应减少。
---------------hash函数------------------
通常键的取值范围比哈希表地址集合大太多,因此有可能经过同一哈希函数的计算,把不同的键映射到了同一个地址上面,这就产生了冲突。
如果“键-值对”在加入哈希表的时候产生了冲突,就必须找另外一个地方来存储它,冲突太多会降低数据插入和查找的效率,因此希望找到一个不容易产生冲突的函数,即构造一个地址分布比较均匀的哈希函数。
常用的hash函数包括:
直接定址法(用于key值为数字或有一定次序规则的情况)、
数字分析法(对key中的数字规则进行分析)、
乘法散列法 将关键字key乘以一个常量A(0<A<1),并且提出key*A的小数部分;然后将这个值乘以m:
h(key)=m*(key*A-(int)(key*A))
乘法散列的一个优势是对m的值没有特别的要求,对应m,一般指定为2的幂。因为这样容易在计算机中实现哈希函数的计算。对常量A,更好的选择是依赖于被散列的数据特征,一般用A等于黄金分割点0.618033.
陈留余数法(%取余法h(key)=key%m,)
其关键是m 的选取,一般选m 为小于某个区域长度n 的最大素数,一般地说,如果 m 的约数越多,那么冲突的几率就越大
简单的证明:假设m 是一个有较多约数的数,同时在数据中存在key 满足最大公约数gcd(m,key)=d >1 ,即 有m=a*d,key=b*d,则有以下等式:key% m= key – m*[key/m] =key – m*[b/a] 。其中,[b / a]的取值范围是不会超过[0,a-1]的正整数。也就是说,[b / a]的值只有a 种可能,而m 是一个预先确定的数。因此上式的值就只有a 种可能了(这显然缩小了余数分布的范围)。这样,取mod 运算之后的余数仍然在[0,m-1]内,但是它的取值仅限于等式可能取到的那些值。也就是说余数的分布变得不均匀了。容易看出,m 的约数越多,发生这种余数分布不均匀的情况就越频繁,冲突的几率越高。而素数的约数是最少的,因此我们选用大素数。所以“m应该最优选择素数”。
平方散列法 由于%包含了*和/的操作,而乘法的运算比除法省时,可以考虑把%变为乘和移位的组合操作对应平方散列法:
可以形如:index=(key*key)>>28
对与平方散列法其实有种改进,通过实验证明这种改进是有效的就是把key*key换成key*一个常数Q,这个常数就来自于斐波那契数列中的值,对于16位整数,Q为40503;32位整数,Q为2654435769;64位整数,Q为11400714819323198485
于是对于常见在32位整数来说,index=(key*2654435769)>>28
平方取中法(key平方后取中间的几位为hash地址)、
折叠法(将key分割成几个部分,叠加求和)、
随机数法(选择一个随机函数,取关键字的随机函数值为它的哈希地址)。
应该根据实际工作中关键码的特点选用适当的方法。
----------------hash冲突---------------
为了避免冲突,选择哈希函数h()的主导思想是使h(k)的出现是“随机”的,即每个关键字都可能散列到任一个地址中去,从而减少冲突的次数。虽然采用合适的哈希方法能够降低冲突的概率,但是冲突仍然是不可避免的:
解决冲突的方法:
(1).链地址法:将具有同一散列地址的记录存储在一条线性链表中。
(2).开放地址法:如果h(k)被占用,就按照如下序列探测:(h(k)+p(1))%TSize,(h(k)+p(2))%TSize,...,(h(k)+p(i))%TSize,...
其中,h(k)为哈希函数,TSize为哈希表的长度,p(i)为探测函数。在(h(k)+p(i))%TSize的基础上,若发现冲突,则使用
增量p(i+1)进行新的探测,直到无冲突为止。
其中,根据探测函数p(i)的不同,开发地址发又分为:
线性探测法(p(i)=i:1,2,3,4,5,6,....);
二次(或平方)探测法:(p(i)=((-1)^(i-1))(i)^2:1,-1,4,-4,9,-9,......)
随机探测法(p(i):为随机数)
双散列函数(双散列函数h(key)、hp(key),如果h(key)出现冲突,则再使用hp(key)求取散列地址)
探测序列为:h(k),h(k)+hp(k), ... ,h(k)+i*hp(k),...
(3). 桶地址法
桶--一片较大的存储空间
“桶”算法:假设哈希表有m个地址,就将其改为m个“桶”,其桶号和哈希地址一一对应,每个桶用来存放互为同义词的键,也就是如果两个不同的键用哈虚函数计算得到了同一个哈希地址,就将它们放到同一个桶中,检索的时候就在桶中进行顺序检索,如果当桶满时可以用开放地址法处理。
-----
当某个bucket中存放的数据非常多时,也就是哈希表中的某个bucket冲突数据非常多时,采用哈希AVL树方式存放这些冲突数据对查找效率会有明显的提高。
-----------------解决分布式缓存的consistent hashing算法-----------------
consistent hashing算法:是一种hash算法,简单地说,在移除/添加一个cache(缓存)时,它能够尽可能小的改变已存在key映射关系,尽可能满足单调性(单调性是指:如果已经有一些内容通过哈希分配到了相应的缓存中,又有新的缓存加入到系统中。哈希的结果应该能够波安装原有已分配的内容可以被映射到新的缓存中去,而不会被映射到久的缓存集合中的其他缓冲区)的要求。
----------扩展 d-left-hashing------------
d-left-hashing,是对传统hash方法的优化和改进,以达到key位置的负载均衡。
其大概思想就是:整个哈希表被分成d个从左到右依次相邻子表,同时有d个相互独立的hash函数,当有key需要hash时,这d个hash函数同时计算,产生d个独立index,然后将key加入到负载最轻的位置中,如果负载最轻的位置有多个(比如同时为空或同时有n个),就把index指定为最左边负载最轻的子表中。
---------------
hash 在对海量数据的处理和密码学方面(如MD5算法)都有很好的应用。
------
后继还会对Hash进一步探索
发表评论
-
Nio Socket
2013-05-16 05:53 0asfda -
结合jdk源码解读,Error Exception
2013-05-10 04:00 0/* * @(#)Error.java 1.17 05/11 ... -
从不同的角度,重新审视class和interface
2013-05-07 03:40 0java开发中,对应class和interface的基本区别都 ... -
java.lang.Object
2013-05-07 03:35 0/* * @(#)Object.java 1.73 06/0 ... -
反射机制+类加载机制
2013-02-18 01:30 0反射机制+类加载机制 -
并发专题----使用开源软件Amino构建并发应用程序/多线程运行时分析工具MTRAT
2013-02-14 00:50 1370使用开源软件构建并发 ... -
并发专题 ---- 线程安全
2013-02-14 00:50 744线程安全 ================== ... -
并发专题 --- 锁
2013-02-14 00:50 802相比于synchronized,ReentrantLock 提 ... -
并发专题 ----(JMM)java内存模型
2013-02-14 00:50 534Java 内存模型 ------------ ... -
并发专题 ---java.util.concurrent 包
2013-02-13 02:26 1832java.util.concurrent 包 原 ... -
集合框架 Queue篇(8)---PriorityBlockingQueue、SynchronousQueue
2013-02-07 12:40 1303Queue ------------ 1.ArrayDeq ... -
集合框架 Queue篇(7)---LinkedBlockingDeque
2013-02-07 12:40 849Queue ------------ 1.ArrayDeq ... -
集合框架 Queue篇(6)---LinkedBlockingQueue
2013-02-07 12:39 827Queue ------------ 1.ArrayDeq ... -
集合框架 Queue篇(5)---ArrayBlockingQueue
2013-02-06 10:39 700Queue ------------ 1.ArrayDeq ... -
集合框架 Queue篇(4)---阻塞队列和生产者-消费者模式、DelayQueue
2013-02-06 10:39 992Queue ------------ 1.ArrayDeq ... -
集合框架 Queue篇(3)---ConcurrentLinkedQueue
2013-02-06 10:38 1043Queue ------------ 1.ArrayDequ ... -
集合框架 Queue篇(2)---PriorityQueue
2013-02-06 10:38 828Queue ------------ 1.ArrayDeq ... -
集合框架 Queue篇(1)---ArrayDeque
2013-02-06 10:38 926Queue ------------ 1.ArrayDeq ... -
集合框架 Set篇---HashSet、LinkedHashSet、TreeSet、CopyOnWriteArraySet、ConcurrentSkipList
2013-02-05 08:43 1477Set --------- 1.HashSet 2.Link ... -
集合框架 List篇(2)---CopyOnWriteArrayList
2013-02-05 08:43 840List ----------- 1.ArrayList(jd ...
相关推荐
哈希表--链表 哈希表--链表 哈希表--链表 哈希表--链表哈希表--链表 哈希表--链表哈希表--链表 哈希表--链表哈希表--链表 哈希表--链表哈希表--链表 哈希表--链表
一致性哈希(Consistent Hashing)是一种在分布式系统中解决数据分片问题的算法,它在Go语言中的实现对于构建可扩展且容错的服务至关重要。在Go开发中,尤其是在涉及分布式缓存、负载均衡等场景下,一致性哈希能够...
#fly-archflylib创立的各种常见的架构技术内容列表cassandra-demo cassandra数据库的入门编程consistent-hash Java implementation of consistent-hashing基于java的一致性hash的实现一致性hash(consistent-hashing)...
使用`ConsistentHashing`库可以简化在分布式系统中实现负载均衡和缓存一致性的工作,如在分布式缓存(如Redis集群)或者分布式数据库中。通过这个库,开发者可以避免手动处理复杂的哈希计算和数据迁移问题,从而更...
理解哈希函数的构造方法和冲突解决策略是设计和使用哈希表的关键,这对于优化算法和提升软件性能具有重要意义。无论是在字典、集合、去重等基本数据结构的实现,还是在字符串匹配、数据压缩、拼写检查等复杂应用场景...
8. 散列在分布式系统中的应用:例如一致性哈希(Consistent Hashing),用于在分布式缓存和分布式数据库中分配节点,保持在节点增减时尽量小的影响。 9. 散列与安全性:在密码学中,散列函数常用于密码存储,通过...
一致性哈希解决了分布式系统中动态添加或移除节点时,数据重新分布的问题。传统的哈希可能导致大量键的重新映射,而一致性哈希通过虚拟节点和哈希环的概念,使得每次节点变化只需少量键迁移。 3. **第三方模块:**...
总结来说,Go语言实现的一致性哈希算法`jump-consistent-hash`以其高效的性能和低内存消耗,成为分布式系统中理想的哈希解决方案。理解并掌握这种算法,对于提升系统设计的灵活性和可扩展性具有重要意义。
基于java的开发源码-哈希计算工具 Java-hash.zip 基于java的开发源码-哈希计算工具 Java-hash.zip 基于java的开发源码-哈希计算工具 Java-hash.zip 基于java的开发源码-哈希计算工具 Java-hash.zip 基于java的开发...
《从标准假设中保留属性的哈希函数》这篇论文探讨了一种特殊类型的哈希函数——属性保留哈希函数(Property-Preserving Hash Functions),这种函数能够在压缩输入数据的同时,保持某些特定属性,允许在仅知道哈希值...
`laravel-hashing-md5`可能是指一个示例项目或教程,专注于使用MD5算法进行哈希操作。虽然MD5在现代安全标准下不再推荐用于密码存储,但了解其在Laravel中的使用仍有一定价值。 Laravel提供了`Hash`门面,它封装了...
一致性哈希(Consistent Hashing)是一种分布式哈希算法,主要应用于分布式缓存、负载均衡等领域,例如在Redis、Memcached等系统中广泛使用。它解决了传统哈希算法在节点动态增减时导致的大量数据迁移问题。在Java中...
2.NGX_HTTP_CONSISTENT_HASH 是一个用于 Nginx 的模块,可以实现基于一致性哈希的负载均衡策略。下载地址:https://github.com/replay/ngx_http_consistent_hash/tree/master,如果打不开,我将我下载的内容上传,...
《Hash表的构建和冲突解决》文档可能详细介绍了如何构建哈希表、各种哈希函数的设计思路,以及在实际编程中如何运用这些方法来有效地解决冲突。可能涉及的具体内容包括: - 哈希表的基本结构和操作(如插入、删除、...
当然,你也可以自定义哈希函数和冲突解决策略以适应分布式环境。 为了实现分布式哈希表,你可能需要以下步骤: 1. 设计节点ID和数据键的哈希函数,确保在整个网络中均匀分布。 2. 实现节点之间的发现和连接机制,...
10. **Java中的冲突解决**: 在Java集合框架中,如HashMap,哈希冲突是通过链表或红黑树来解决的。当两个键的哈希值相同但键本身不同时,它们会被放入同一个桶中,形成链表或红黑树结构。 综上所述,`java-hash.7z` ...
《The Joys of Hashing》这本书将教会读者如何用C语言创建和操作哈希表,包括如何设计哈希函数、如何处理哈希冲突、如何调整哈希表的大小来优化性能等。通过阅读这本书,读者将获得宝贵的技能,能够在需要高效数据...
在设计该系统时,我们使用了除留余数法构造哈希函数,然后使用线性探测再散列解决冲突。系统的实现语言为C++,运行环境为Windows XP Professional。 哈希函数是一种非常有用的数据结构技术,广泛应用于各种领域。...
lua 一致性哈希基于 yaoweibin 的一致性哈希分支( )在 lua 中重新实现一致性哈希用法 local chash = require " chash "chash. add_upstream ( " 192.168.0.251 " )chash. add_upstream ( " 192.168.0.252 " )chash...