【发布时间】:2015-09-30 20:07:08
【问题描述】:
一般来说,字符串搜索算法(如 Boyer-Moore)针对 搜索字符串 较长的情况进行了优化。也就是说,Boyer-Moore 很棒,因为通过将搜索字符串与我们的文本对齐,如果搜索字符串的结尾与文本不匹配,我们可以跳过 N = len(search string) 字符。
但是如果我们的搜索字符串真的很短怎么办?像单个字节或字符?在这种情况下,Boyer-Moore 没有多大帮助。
那么,有哪些替代算法可以加快搜索速度?
我知道许多优化的库搜索例程(如 C 中的memchr),采用逐字读取输入字符串的策略,而不是逐字符读取。所以在 64 位机器上,一次可以检查 8 个字节,而不是单个字节。
我想知道这些优化的字符串/字节搜索实际上是如何工作的。那么实际的比较是如何进行的呢?我知道它显然必须涉及位掩码 - 但我看不出执行所有位掩码比简单地逐个字符搜索更好。
所以,假设我们的搜索字符是0xFF。忽略对齐问题,假设我们有一些输入缓冲区:void* buf。我们可以逐字阅读:
const unsigned char search_char = 0xFF;
unsigned char* bufptr = static_cast<unsigned char*>(buf);
unsigned char* bufend = bufptr + BUF_SIZE;
while (bufptr != bufend)
{
// Ignore alignment concerns for now, assume BUF_SIZE % sizeof(uintptr_t) == 0
//
std::uinptr_t next_word = *reinterpret_cast<std::uintptr_t*>(bufptr);
// ... but how do we compare next_word with our search char?
bufptr += sizeof(std::uintptr_t);
}
我也意识到上面的代码不是严格可移植的,因为不能保证std::uintptr_t 实际上是字长。但是,为了这个问题,我们假设std::uinptr_t 等于处理器字长。 (实际实现可能需要特定于平台的宏来获取实际字长)
那么,我们如何实际检查字节 0xFF 是否出现在 next_word 的值中的任何位置?
我们当然可以使用OR 操作,但似乎我们仍然需要执行大量的 OR'ing 和位移来检查next_word 的每个字节,此时这种优化是否会成为问题实际上比简单地逐个字符扫描要好。
【问题讨论】:
-
为了加快搜索速度,您需要更改数据结构,例如对其进行排序或使用链表或哈希生成器。有时,对于小数据,蛮力线性搜索是您最快的选择。一些处理器具有在内存中搜索字节的专门功能。
-
如果要搜索的数据很大,可以考虑使用多线程进行搜索。这种技术的一个棘手问题是设置线程的开销。理想情况下,您可以将线程处理委托给内核,例如 GPU 或处理器中的内核。
-
可能看到this page
-
我知道加快搜索的所有问题 - 对于庞大的数据集,像后缀树这样的东西可能很有用。我只是专门询问使用一次阅读一个单词的优化单字符搜索。我只是想了解实际的比较是如何完成的——为了加快搜索速度,做了哪些按位逻辑?
-
@Hasturkun - 谢谢这正是我想要的。如果您将其发布为答案,我会接受它
标签: c++ string-search