我在C中编写程序,设计为快速。
我想在数据流中存储IP地址的出现次数。例如,我将分析100MB二进制文件,其中包含大约2 000 000个IP地址(但也许程序也将用于x-GB文件)。
我的想法是使用哈希表,所以我需要这些哈希函数:
20b_int indexToIPv4HashTable = hashIPv4(32b_int addr4);
20b_int indexToIPv6HashTable = hashIPv6(128b_int addr6);
我觉得这个函数在某个时候会发生碰撞并不是问题(我将使用单独链接来解决这个问题)。
小数学:
注意: IP地址可能已指定掩码。例如:IPv4 / 24 - >现在只有2 ^ 24个不同的IPv4地址而不是2 ^ 32。 当设置掩码时,我应该使用不同的哈希表大小吗?
绝对优先考虑的是速度。
答案 0 :(得分:3)
顺便说一下,我假设您的意思是4Gb,而不是4Mb,因为上面的32位索引大小。此外,假设您每个条目只需要一个字节(最多255次点击)
如果不知道地址的分布,很难知道哪个哈希会更好。如果它们或多或少地随机分布在地址空间(是的,我知道大多数IPv6地址都没有分配),只需选择一些地址并使用它。
例如,选择5个4位区域均匀分布在ipv4的地址中,最低16位+ 4位从中间位置为v6。
但是如果你使用crc32指令处于现代x86上几乎肯定会产生足够好的哈希值,并且速度很快。
#define HASH_MASK ((1<<20)-1)
static inline int hash32( unsigned int foo )
{
return __builtin_ia32_crc32si( 0, foo ) & HASH_MASK;
}
static inline int hash128( const char *data )
{
int res = 0, i;
for( i=0; i<4; i++, data+=4 )
res = __builtin_ia32_crc32si( res, *(int32_t *)data );
return res & HASH_MASK;
}
请注意,这是非常不可移植的,它不仅适用于x86,它只适用于某些x86机器(如果使用gcc,它还需要-msse4.2)。
一个注意事项:除非你每秒处理大量的条目(我的确意味着很多),否则哈希函数的速度不太重要。 散列桶中的数据传播可能会影响事物,但即使链接列表桶散列表的简单非调整大小实现也能够每秒处理至少数亿次点击,除非链接变为100+长。 事实上,从中读取硬盘驱动器的速度很可能是限制因素。