注意点:
1. hashing的复杂度为O(1)或O(L),若是字符串,为字符串的长度L
2. HashMap查找key的方法为containsKey(key), HashSet为contains(key)
HashMap添加方法为put(key, value), HashSet为add(key)
3. HashMap有这两个常用、易忽略方法:
keySet();//得到键set
values()//返回一个值的集合
一. Hashing
1.
Java中的hash code对于整数是以整数的值生成,string是以31基的指数生成。
例如:Integer 8722 的 hashCode为8722
String “8722”的hashCode为Math.pow(31, 3) * 56 + Math.pow(31, 2) * 55 + Math.pow(31, 1) * 50 + Math.pow(31, 0) * 50 其中56、55、50分别是872的ascii码。
不相等的两个对象可能有相同的hashcode,会产生collisions。
有相等的对象必须有相同的hashcode(所以重写equals时必须重写hashcode方法)。
2.hash function
好的hash function需要计算迅速(少乘除法)。
同时对随机key和非随机key处理方法不同。对随机正key value来说,如上简单实现即可。对于非随机key(例如身份证号等有意义的数字),要根据数据的范围和数据的意义来hash, 比如(1)不要用无效数据,要根据数据范围和数据特征来变换,比如数据都是十的倍数,则可以节省一位。(2)用所有的数据。不能用只前几位等方式hash。(3)用质数hash.(4)folding 比如123-456-789加入1009的table,则可以用(123 + 456 + 789) %1009来实现。
其它:
对比int和Integer:int是primary type,Integer是reference type。int 8722没有hashCode,而Integer8722有hashCode。用==比较时,比的是指针,Integer和String相似。
选择31是因为31是质数(不是质数会出现死循环)且分布结果好。不过也有实验证明,37等质数一样有好的分布结果。
二. HashTable
HashTable可由Open Address处理冲突,也可由分离式链表Separate Chaining处理冲突。
java collection中以分离式链表实现。
1.实现方法
(1)得到key
(2)hashVal = key % table.length
(3)如果长度大于2/3则rehashing。否则load factor很大时,hash表的查找时间会变得非常慢。而rehashing时time consuming的,它需要将原table扩大二倍,再重新调用hash方法处理每一个旧数组里的对象。
/需要注意的是,hash表除了“有”和“无”两种状态,还需要一个“Deleted”状态,防止某一节点被删除后,后面节点也的找不到。
2. Open Address
(需要注意的是,hash表除了“有”和“无”两种状态,还需要一个“Deleted”状态,防止某一节点被删除后,后面节点也的找不到)
2.1 collisions
openAddress的主要思想是,遇到冲突不断进行位移。
解决collision的方法:1.线性方法(x, x+1, x+ 2......)2.平方方法(x, x + 2, x + 4.......)3.双重hash(double hashing) ---(双重hash待补充)
2.2优缺点
线性方法会产生 聚合效应:插入的点容易聚集到一起,以后每一次搜索该区域都要线性时间。
平方方法会产生 次聚合效应:第一次hash到同一位置的点,以后每一次搜索经过的路线均一样。
三. Hash Map, Hash Set
hash map是键值对,hash set存放单一对象。二者均不能有相同的key的值,新对象加入会替换相同key的旧对象。
1. HashMap的方法:
put(key, value)
get(key)
keySet();//得到键set
values()//返回一个值的集合
https://blog.csdn.net/tjcyjd/article/details/11111401 遍历
2.HashSet的方法
add(key);
contains(key);
iterator()