zoukankan      html  css  js  c++  java
  • Hash算法,及HashMap使用

    为什么要Hash?

    哈希表是基于数组实现的,哈希算法就是如何将键值(key)转换成数组小标的方法,哈希化可以提供非常高的操作(插入、删除、查询)效率,因为对有序数组的查询,即使是二分查找也只能做到O(logN),因为哈希可以直接将要查询的key转化为数组小标,所以可以达到O(1)的时间级。


    Hash算法:将key做hash后的值叫hashcode,hashcode的值范围可能很大,Hash算法是将一个较大范围的hashcode转换为定长的区间的数值。一个好的hash算法应该使hashcode均匀分布在区间内。 但是难免还是会有不同的key会产生相同的hashcode,此为哈希冲突。

    例如,要对公司100个雇员的信息做哈希存储,要求以姓名作为键值,“frank” 的hashcode是3135416,如果直接用3135416做小标,意味着要用一个非常大的数组,显然非常浪费。mod是最简单,往往也是最有效的hash算法,3135416%100=16,这样就可以用array[16]来存储“frank”的信息了。


    如何解决哈希冲突?

    1. 开放定址法
      线性探测,二次探测,再哈希。
      例如“leo”的hashcode是733616,用模100哈希算法后,其值也是16,因为array[16]已经被占用了,产生了“冲突”,那么顺序查看16的下个位置17,看array[17]是否可用,如果可以则存储leo,否则继续探测下个位置18,直到有空位为止。在查询时,若一个key的哈希值为16,不能就简单的返回array[16],因为哈希值为16的可能是frank 或者 leo,所以还要比对key值。
    2. 链地址法
      Java 的 HashMap就是用LinkedList解决hash冲突的。

    参考:http://en.wikipedia.org/wiki/Hash_function


    使用Java HashMap时,注意以下几点:

    1. HashMap不是线程安全的

    不要在并发环境中使用HashMap,这样会造成不可预期的后果,据sun的说法,在扩容时,会引起链表的闭环,在get元素时,就会无限循环,后果是cpu100%。

    如果Concurrent is a must,请用Map m = Collections.synchronizedMap(new HashMap(...))

    2.如果数据大小是固定的,那么最好给HashMap设定一个合理的容量值

    因为HashMap的默认容量是Capacity(16) * LoadFactor(0.75) = 12,如果你的HashMap是用来装载1万条数据的,那么HashMap会不断的扩容(resize),而每次扩容都会对原有数据做重新排列,非常的time-consuming,所以应该在初始化HashMap的时候用New HashMap(15000),负载因子(loadFactor)用默认的0.75就好了。

    More about loadFactor:这个loadFactor有做什么用得呢? 是用来减少collision的,试想一下, 是不是越接近满载的时候,产生冲突的可能性越大呢,就像公交车上有16个座位,此时上来5个人,几乎不会出现抢位子的情况,因为很空。假如又上来10个人,那么15个人对16个座位,可能有些人觉得前面座位比较好,就会产生冲突并问候对方的父母。现在规定这个16座的公交车只允许载客12人,也就是负载因子是0.75,后面来的人用另一辆空车装载,这样就可以有效的解决冲突。

    3.成为HashMap的key的条件

    HashMap是用一个数组Entry[ ]来存储相应的Entry<K, V>的,所以在put(K, V)操作时,首先检查Key的hashCode,看该Entry在数组中是否已经存在,若不存在,加到数组中,否则,会再将K.equals()于现有已存在数组中得Entry的链表(linked list)中的K进行比较,若有相同的,将其替换, 若没有,将该Entry置于链表的头部。

    在get( )操作是,是先查看HashCode,再比较equals,两者皆匹配的时候,才会返回Value。

    所以这是为什么要作为HashMap的key要override hashCode 和 equals的原因。

    参考:http://www.iteye.com/topic/754887

    4. HashMap 和 HashTable, HashSet的比较

    1.Hashtable是Dictionary的子类,HashMap是Map接口的一个实现类;
    2.Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。
    3.HashMap 允许key和value为null,HashTable则不允许
    4. HashTable直接用对象的hashCode,HashMap有自己的hash算法
    5. HashSet不是Map是Set,其与ArrayList的区别是HashSet不允许重复元素,可通过HashMap.keySet()获得HashMap中key的set

    发现一个对hash深入研究的博文,以及用hash做Top K 问题的solution (有1000万条(查询串)记录,找出里面top 10出现次数最多的查询串的方法)

    http://blog.csdn.net/v_july_v/article/details/6256463


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    Codeforces 405E DFS
    Codeforces 433C #248_div1_A 中位数的应用
    UVALive 4487 Exclusive-OR 加权并查集神题
    Codeforces 442A Borya and Hanabi
    人工智能:实现人工智能是是不可能的吗?
    关于kinect开发的网址
    jsp笔记(1)
    关于Kinect音频开发的探究
    windows10添加电源计划修改的快捷方案
    关于 kinect 的开发
  • 原文地址:https://www.cnblogs.com/significantfrank/p/4875853.html
Copyright © 2011-2022 走看看