Time33哈希算法

Time33哈希算法

转载自:http://blog.csdn.net/chen_alvin/article/details/5846714

接到任务,需要编程求两个十万级记录列表的交集。分析后,有两个解决思路:一、在数据库中建立临时表,导入数据后,用SQL语句才交集,再导出数据;二、直接内存运算求解。考虑到数据记录多,数据库运算压力大,最后决定选择第二个方法。

 

涉及到数据查找比对,首先考虑到使用HashSet。HashSet最大的好处就是实现查找时间复杂度为O(1)。使用HashSet需要解决一个重要问题:冲突问题。对比研究了网上一些字符串哈希函数,发现几乎所有的流行的HashMap都采用了DJB Hash Function,俗称“Times33”算法。Times33的算法很简单,就是不断的乘33,见下面算法原型。

 

[cpp]  view plain copy
  1. hash(i) = hash(i-1) * 33 + str[i]  

 

 

Time33在效率和随机性两方面上俱佳。对于一个Hash函数,评价其优劣的标准应为随机性,即对任意一组标本,进入Hash表每一个单元(cell)之概率的平均程度,因为这个概率越平均,数据在表中的分布就越平均,表的空间利用率就越高。

 

 

[java]  view plain copy
  1. int Time33(String str) {  
  2.     int len = str.length();  
  3.     int hash = 0;  
  4.     for (int i = 0; i < len; i++)  
  5.         // (hash << 5) + hash 相当于 hash * 33  
  6.         hash = (hash << 5) + hash + (int) str.charAt(i);  
  7.     return hash;  
  8. }  

 

 

Java的HashSet判断冲突,主要依靠对象的HashCode和equals方法。因此对象必须重写hashCode和equals两个方法。

以下测试构造300,0000个Item对象,放入到HashSet中,测试Time33算法。

 

 

[java]  view plain copy
  1. /** 
  2.  * Item类 
  3.  * 重写hashCode和equals方法 
  4.  */  
  5. class Item {  
  6.     public Item(String[] strs) {  
  7.         columns = strs;  
  8.     }  
  9.   
  10.     public boolean equals(Object otherObject) {  
  11.         if (this == otherObject)  
  12.             return true;  
  13.         if (otherObject == null)  
  14.             return false;  
  15.         if (getClass() != otherObject.getClass())  
  16.             return false;  
  17.         if (!(otherObject instanceof Item))  
  18.             return false;  
  19.         Item other = (Item) otherObject;  
  20.         if (this.columns.length != other.columns.length)  
  21.             return false;  
  22.         for (int i = 0; i < this.columns.length; i++) {  
  23.             if (this.columns[i] != null && !this.columns[i].equals(other.columns[i]))  
  24.                 return false;  
  25.         }  
  26.         return true;  
  27.     }  
  28.   
  29.     public int hashCode() {  
  30.         StringBuffer sb = new StringBuffer();  
  31.         for (int i = 0; i < this.columns.length; i++) {  
  32.             sb.append(this.columns[i]);  
  33.         }  
  34.         return this.Time33(sb.toString());  
  35.     }  
  36.   
  37.     private int Time33(String str) {  
  38.         int len = str.length();  
  39.         int hash = 0;  
  40.         for (int i = 0; i < len; i++)  
  41.  

    1.            hash = (hash << 5) + hash + (int) str.charAt(i);  
    2.         return hash;  
    3.     }  
    4.   
    5.     private String[] columns;  
    6. }  

     

     

     

    [java]  view plain copy
    1. HashSet<Item> hashSet = new HashSet<Item>();  
    2. long start;  
    3. long end;  
    4. String[] strs = { "Alvin""Chan""HashSet""WOW" };  
    5. String[] tmp;  
    6. int count = 0;  
    7.       
    8. start = System.currentTimeMillis();  
    9.   
    10. for (int i = 0; i < 3000000; i++) {  
    11.     tmp = new String[4];  
    12.     for (int j = 0; j < 4; j++) {  
    13.         // 用strs中随机抽取字符串,并加入随机数,生成tmp字符串数组  
    14.         tmp[j] = strs[(int) (Math.random() * 3)] + (int) (Math.random() * i);  
    15.     }  
    16.     // 加入无法插入到hashSet中,计数器加1  
    17.     if(!hashSet.add(new Item(tmp))) {  
    18.         count++;  
    19.     }  
    20. }  
    21.   
    22. end = System.currentTimeMillis();  
    23.   
    24. System.out.println("插入300,0000条记录");  
    25. System.out.println("所需时间:" + (end - start) + " ms");  
    26. System.out.println("插入个数:" + hashSet.size());  
    27. System.out.println("失败次数:" + count);  

     

     

    测试运行了5次,结果如下:(数据量较大,建议加大JVM的内存再运行测试,否则会内存溢出)

     

    [java]  view plain copy
    1. 1次  
    2. 插入300,0000条记录  
    3. 所需时间:34203 ms  
    4. 插入个数:3000000  
    5. 失败次数:0  
    6.   
    7. 2次  
    8. 插入300,0000条记录  
    9. 所需时间:33063 ms  
    10. 插入个数:3000000  
    11. 失败次数:0  
    12.   
    13. 3次  
    14. 插入300,0000条记录  
    15. 所需时间:33016 ms  
    16. 插入个数:3000000  
    17. 失败次数:0  
    18.   
    19. 4次  
    20. 插入300,0000条记录  
    21. 所需时间:33062 ms  
    22. 插入个数:3000000  
    23. 失败次数:0  
    24.   
    25. 5次  
    26. 插入300,0000条记录  
    27. 所需时间:33140 ms  
    28. 插入个数:3000000  
    29. 失败次数:0  

     

     

    从测试结果来看,面对百万级条记录,使用了Time33作为哈希函数的HashSet能较好地解决冲突问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值