程序员必备:字符串哈希函数比较

本文探讨了在股票交易系统中用于快速查找的哈希函数选择,比较了BKDRHash、APHash、JSHash等9种哈希算法,并通过实验统计在不同字符串集合中的性能,发现JSHash、DJBHash和FNVHash具有优秀的分布性,适用于减少冲突。建议在实际应用前,根据具体数据集测试哈希函数的性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个股票交易系统的后台,为了能快速查找各种股票代码的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的哈希
bkdrhash5097214
aphash5197215
jshash4946615
rshash5057415
sdbmhash5186715
pjwhash75613134
elfhash80115891
djbhash5126417
dekhash5367522
bphash1391696690
fnvhash5166514
javahash52369 16

结论

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值