一致性hash算法--字符串哈希函数比较

一个股票交易系统的后台,为了能快速查找各种股票代码的Tick,会计算其哈希值,然后存贮在哈希表里面。一个好的哈希函数应该能实现很好地分布性,减少冲突。这里选取了几种常用的字符串哈希,包括BKDRHash,APHash,JSHash,RSHash,SDBMHash,PJWHash,ELFHash和DJBHash,通过在不同的字符串集合测试,来测试其性能。

各种常用算法

一、BKDRHash

BKDRHash是Kernighan和Dennis在《The C programming language》中提出的。这个算法的常数131是如何选取的,尚未可知,有知情者可以留言。

public static int bkdrhash(String str) {
      final int seed = 131;

      int hash = 0;

      for (int i = 0; i < str.length(); i++) {
         hash = hash * seed + (int)str.charAt(i);
      }

      return hash & 0x7FFFFFFF;
   }

二、APHash

Arash Partow提出了这个算法,声称具有很好地分布性。

public static int aphash(String str) {
      int hash = 0;

      for (int i = 0; i < str.length(); i++) {
         if ((i & 1) == 0) {
            hash ^= (hash << 7) ^ (str.charAt(i)) ^ (hash >> 3);
         } else {
            hash ^= ~((hash << 11) ^ (str.charAt(i)) ^ (hash >> 5));
         }
      }

      return hash & 0x7FFFFFFF;
   }

三、JSHash

Justin Sobel提出的基于位的函数函数。

public static int jshash(String str) {
      int hash = 0;

      for (int i = 0; i < str.length(); i++) {
         hash ^= (hash << 5) + (int)str.charAt(i) + (hash >> 2);
      }

      return hash & 0x7FFFFFFF;
   }

四、RSHash

其作者是Robert Sedgwicks。实现如下:

public static int rshash(String str) {
      int hash = 0;

      int a = 63689;
      final int b = 378551;

      for (int i = 0; i < str.length(); i++) {
         hash = hash * a + (int)str.charAt(i);
         a *= b;
      }

      return hash & 0x7FFFFFFF;
   }

五、SDBMHash

SDBM项目使用的哈希函数,声称对所有的数据集有很好地分布性。

public static int sdbmhash(String str) {
      int hash = 0;

      for (int i = 0; i < str.length(); i++) {
         hash = (int)str.charAt(i) + (hash << 6) + (hash << 16) - hash;
      }

      return hash & 0x7FFFFFFF;
   }

六、PJWHash

Peter J. Weinberger在其编译器著作中提出的。

public static int pjwhash(String str) {
       int BitsInUnignedInt = 32;
       int ThreeQuarters    = 24;
       int OneEighth        = 4;
       int HighBits         = (int)(0xFFFFFFFF) << (BitsInUnignedInt - OneEighth);
       int hash             = 0;
       int test             = 0;

       for (int i = 0; i < str.length(); i++) {
           hash = (hash << OneEighth) + (int)str.charAt(i);
           if ((test = hash & HighBits) != 0)
           {
               hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
           }
       }

       return hash & 0x7FFFFFFF;
   }

七、ELFHash

Unix系统上面广泛使用的哈希函数。

public static int elfhash(String str) {
      int hash = 0;
      int x = 0;

      for (int i = 0; i < str.length(); i++) {
         hash = (hash << 4) + (int)str.charAt(i);

         if ((x & hash & 0xF0000000L) != 0) {
            hash ^= x >> 24;
            hash &= ~x;
         }
      }

      return hash & 0x7FFFFFFF;
   }

八、DJBHash

Daniel J. Bernstein在comp.lang.c邮件列表中发表的,是距今为止比较高效的哈希函数之一。

public static int djbhash(String str) {
      int hash = 5381;

      for (int i = 0; i < str.length(); i++) {
         hash += (hash << 5) + (int)str.charAt(i);
      }

      return hash & 0x7FFFFFFF;
   }

九、DEKHash

Donald E. Knuth在《计算机程序设计的艺术》中提出的哈希函数。

public static int dekhash(String str) {
      int hash = str.length();

      for (int i = 0; i < str.length(); i++) {
         hash = (hash << 5) ^ (hash >> 27) ^ (int)str.charAt(i);
      }

      return hash & 0x7FFFFFFF;
   }

十、BPHash

public static int bphash(String str) {
      int hash = str.length();

      for (int i = 0; i < str.length(); i++) {
         hash = (hash << 7) ^ (int)str.charAt(i);
      }

      return hash & 0x7FFFFFFF;
   }   

十一、FNVHash

public static int fnvhash(String str) {
      int fnvprime = 0x811C9DC5;
      int hash = 0;

      for (int i = 0; i < str.length(); i++) {
         hash *= fnvprime;
         hash ^= (int)str.charAt(i);
      }

      return hash & 0x7FFFFFFF;
   }

十二、Java String Hashcode

这是Java的字符串类的Hash算法,简单实用高效。直接从JDK6里面拿出来的代码:

public static int javahash(String str) {
      int hash = 0;

      for (int i = 0; i < str.length(); i++) {
         hash = hash * 31 + (int)str.charAt(i);
      }

      return hash & 0x7FFFFFFF;
   }   

实验统计

使用网上提供的一份英语单词文件:http://www.cs.duke.edu/~ola/ap/linuxwords,共45402个单词,分别比较上面每一个算法在哈希表长度为100,1000和10000时的最大冲突数,理论上平均为455,46和5。结果如下:

算法 长度100的哈希 长度1000的哈希 长度10000的哈希
bkdrhash 509 72 14
aphash 519 72 15
jshash 494 66 15
rshash 505 74 15
sdbmhash 518 67 15
pjwhash 756 131 34
elfhash 801 158 91
djbhash 512 64 17
dekhash 536 75 22
bphash 1391 696 690
fnvhash 516 65 14
javahash 523 69 16

结论

从上面的统计数据可以看出对英文单词集而言,jshash,djbhash和fnvhash都有很好地分散性。在开始实现股票交易系统前,可以先获取一份比较全面的股票代码,详细比较各种算法的性能,从而可以获得对系统性能的一个估计。

原文地址:https://blog.csdn.net/alburthoffman/article/details/19641123

猜你喜欢

转载自blog.csdn.net/u012834750/article/details/80005162
今日推荐