每个比特都是独立的,因此在预处理阶段[*]中,您可以将每个条目分类32次(或者您的
int
有多大)。每个分类存储2个集合:当
key
为0时,在该位匹配的那些和当
key
为1时匹配的那些。
也就是说,如果值等于1且掩码在该位上等于0,则该分类根本不存储该条目,因为它不与任何
key
的值匹配(实际上,无论使用什么方案,在任何预处理阶段中都应删除这样的条目,因此
没有分类应存储一个条目,即使只有一位是这样的情况)。如果两个都是0,则存储到两个集合中。否则,存储到两个集合中的一个。
然后,给定您的键,您希望快速查找32个集合的交集。
根据原始数组的大小,存储每个集合的最佳方法可能是一个巨大的位数组,指示数组中的每个条目是否在集合中。然后可以一次一个字地找到交集-从每个位数组中取出32个字,并将它们
&
在一起。如果结果为0,请继续。如果结果为非零,则表示匹配,而在结果中设置的位告诉您哪个条目是匹配项。当然,这仍然与数组大小成线性关系,并且实际上您正在执行31个
&
操作以检查32个条目是否匹配,这与简单的线性搜索原始数组大致相同。但是,比较和分支更少,您查看的数据更加压缩,因此可能会获得更好的性能。
或者可能有更好的方法来执行交集。
如果键倾向于被重复使用,则应将查找结果缓存到从键到条目的映射中。如果可能的键数目相当小(即,如果可能输入的键明显少于2^32个,和/或您有大量可用内存),则您的预处理阶段可以仅为:
1. 逐个获取每个条目
2. 确定它与哪些可能的键匹配
3. 将其添加到这些键的映射中
[*] 没有任何预处理,显然您只能检查每个数组成员,直到找到匹配项或检查了所有内容。
(value & mask) == value
条件的条目丢弃,因为它们永远不会匹配。 - SF.