用java实现hashmap
虽然很想很早就想写一个hash表,但一直都未去实现。通过这次机会,算是对hash表有了一个比较直观的了解,主要有以下几点(都是个人见解):
1.哈希表的目的在于加快查找速度,用一个形象的比喻就是hash是将一个排好序的数据存入 数组中,所以在查找时能通过这个索引迅速找到所需要的元素,在hash表中,数组才是主体,链表只是辅助,甚至可以不存在。
2.产生这个索引(在hash中是key)的函数和方法各种各样,而判别这个方法优劣就是让其尽可能少得产生冲突,因为产生冲突后,就会调用处理冲突的方法,无论哪一种方法都不是很合适,以链表为例,显然链表是不适合查找的,所以这个方法对表性能的影响是很大的。这里我才用了和系统差不多的方法,采用了&运算,其实类似于mod,但速度更快。
3.处理冲突的方法也有不少。其中我比较明白的是再散列法和拉链法。在散列法的思想很简单,就是产生冲突后重新计算hash函数地址(索引值)直到找到空的空间放数据。而拉链法则是运用的链表的逻辑连续特性,使不同的数据存在同一个哈希地址下。我采用了第二种,所以对其优缺点比较了解,缺点很明显就是增加查找的复杂度,而相对与再散列法的优点还是很大的,可以避免重复的计算hash地址。
4.如何resize,当装载数与数组长度的比例大于等于比例因子,这是说明数组容量快要饱和,为了避免产生大量的冲突,必须采用resize。
而在写代码的过程中也考虑了很久。比如在数组中存什么,数组长度定义多少之类。这里我说说我的方法。数组中我存的是链表的首节点,因为链表的特性,只要知道头就可以获得整个链表,于此匹配的,我也采用了头插法,当产生冲突,我把它放在链表的头位置。这样代码可以减少不少。至于数组长度我定义为2^n,原因与&运算有关,因为2^n-1的二进制所有位都为1,这样的与运算可以使冲突尽量减少。当产生冲突时,数组长度扩大一倍,感觉也是比较合理的。
以下是部分代码
写的比较急,没怎么优化。
以下是测试类。我用1000000个连续的号码进行存储和查找的测试。系统的时间大概在2600ms,我的大概在3000ms。查找100000个数据,我的约为90ms,系统在120ms左右,当然这和我的node设置的针对性也有关系。
以下是myhashmap的测试主函数(将da放的位置改变就可以测试不同的时间)
hash的内容还有很多,先写到这。至于哈希算法,很多在安全领域涉及,比如MD5(深奥啊),以后再补充吧。