我需要(非常)快速处理有限范围的字符串,计算它们的值。输入文件的格式为:
January 7
March 22
September 87
March 36
等等。因为线宽是相同的,所以我可以以fread
相当快的速度简单地阅读一行,并且我开发了一个完美的散列函数,它可以工作,但我想看看是否有人可以就如何让它更快地提供任何建议。我将分析每个建议,看看它是如何进行的。
散列函数基于月份名称,以允许将值快速分配到存储桶。在这里忍受我。我首先计算出完美哈希的最少字符数:
January
February
March
April
May
June
July
August
September
October
November
December
请记住,月份都是九个字符,因为我有整个输入行。
不幸的是,没有单一的列来标记月份的唯一性。第 1 列重复J
,第 2 列重复a
,第 3 列重复r
,第 4 列重复u
和第 5 列向前重复<space>
(还有其他重复,但一个足以防止单列哈希键)。
但是,通过使用第一列和第四列,我得到了唯一的值Ju
, Fr
, Mc
, Ai
, M<space>
, Je
, Jy
, Au
, St
, Oo
,Ne
和。De
此文件中不会有无效值,因此我不必担心输入数据的存储桶不正确。
通过查看字符的十六进制代码,我发现我可以通过与战略值进行 AND 运算来获得较低的唯一值:
FirstChar Hex Binary &0x0f
--------- --- --------- -----
A x41 0100 0001 1
D x44 0100 0100 4
F x46 0100 0110 6
J x4a 0100 1010 10
M x4d 0100 1101 13
N x4e 0100 1110 14
O x4f 0100 1111 15
S x53 0101 0011 3
SecondChar Hex Binary &0x1f
---------- --- --------- -----
<space> x20 0010 0000 0
c x63 0110 0011 3
e x65 0110 0101 5
i x69 0110 1001 9
o x6f 0110 1111 15
r x72 0111 0010 18
t x74 0111 0100 20
u x75 0111 0101 21
y x79 0111 1001 25
这让我可以设置一个静态数组来创建一个(希望)令人眼花缭乱的快速哈希函数:
#define __ -1
static unsigned int hash (const char *str) {
static unsigned char bucket[] = {
// A S D F J M N O
__, __, __, __, __, __, __, __, __, __, __, __, __, 4, __, __, // space
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, __, __, __, __, __, __, __, 2, __, __, // c
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, 11, __, __, __, __, __, 5, __, __, __, 10, __, // e
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, 3, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // i
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, 9, // o
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, 1, __, __, __, __, __, __, __, __, __, // r
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, 8, __, __, __, __, __, __, __, __, __, __, __, __, // t
__, 7, __, __, __, __, __, __, __, __, 0, __, __, __, __, __, // u
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
__, __, __, __, __, __, __, __, __, __, 6, __, __, __, __, __ // y
};
return bucket[((unsigned int)(str[3]&0x1f)<<4)|(str[0]&0xf)];
}
用代码测试:
#include <stdio.h>
#include <string.h>
// Hash function here.
static char *months[] = {
"January ", "February ", "March ", "April ", "May ", "June ",
"July ", "August ", "September", "October ", "November ", "December "
};
int main (void) {
int i;
for (i = 0; i < sizeof(months)/sizeof(*months); i++)
printf ("%-10s -> %2d\n", months[i], hash(months[i]));
return 0;
}
表明它在功能上是正确的:
January -> 0
February -> 1
March -> 2
April -> 3
May -> 4
June -> 5
July -> 6
August -> 7
September -> 8
October -> 9
November -> 10
December -> 11
但我想知道它是否可以更快。
有什么建议吗?如果我的散列函数本身存在问题,我愿意接受任何简单的优化,甚至完全重写。
我认为这并不重要,但最终版本将使用 EBCDIC。该理论仍然有效,但由于字符具有不同的代码点,AND 操作可能会略有变化。我会很高兴仅在 ASCII 方面提供任何帮助,因为我相信所提供的任何建议都可以转化为 EBCDIC。