一本高效的字符串词典

An efficient dictionary of strings

本文关键字:字符串 高效 一本      更新时间:2023-10-16

我有一个数据结构问题。我有一个字符串集合,它在进程的整个生命周期中不断增长。我希望能够以不同的持续时间在程序中传递对这些字符串的引用。我不想向集合中添加重复项,所以当我传入一个时,我希望返回对现有条目的引用,因此:

const std::string& add_new_entry(const std::string&)
{
    // Check if string exists
    // Return reference if it does
    // Otherwise add to collection
    // Return reference to it
}

最天真的实现是一个字符串列表和每次调用std::find,但我忍不住觉得这是次优的,尤其是因为我要处理超过50000个字符串。我已经创建了一个扩展数组容器,这样我就可以在不强制调整大小和移动的情况下任意添加元素,并且我正在使用取消引用比较谓词按字母顺序排列std::string*std::set对它们进行索引:有人能做得更好吗?15个字符串的比较似乎很多。

要消除setO(log n)性能,可以使用使用哈希的unordered_set(也是O(1))(或者本质上相同的hash_set,但仅受某些编译器支持)。

假设您正在进行(最多)15个字符串比较,但并不是一直都达到这个最大值,而且其中许多字符串只能比较一个或两个字符,那么生成unordered_set的哈希(以及处理哈希冲突)很可能比在set中查找值花费更长的时间。

另外,为什么不去掉数组,只使用std::set<std::string>呢?你仍然可以返回一个参考所有相同:

const string& add_new_entry(const string& str)
{
    set<string>::iterator iter = yourSet.find(str);
    if (iter == yourSet.end())
      return *yourSet.insert(str).first;
    return *iter;
}

测试。

优化总是可能的,偶尔也很有价值,但对于50000个条目,我猜这可能没有必要。考虑到这确实是必要的,你可以尝试一些事情。

首先,如果某些词条的使用频率比其他词条高,你可以将它们存储在一个单独的流行词词典中,然后先搜索。要查看这是否值得,请针对每个字典条目存储一个计数器,每次访问条目时都递增,并在长时间的测试期间查看这些计数器。

另一个值得拥有的东西是一个固定大小的字典数组,比如26^3=117576,其中条目的前三个字母用于选择要搜索的字典。对于三个字母或三个字母以下的单词,这会将您的搜索次数降到o(1),并大大减少您对其余条目的搜索时间。

使用映射。您不必搜索您的数组/列表。

我可能只会使用std::set,可能会将其迭代器包装在一个小类中,检查是否无效,这样您就可以保留迭代器而不是指针。

不要过早地进行优化。你对那个代码进行了简介吗?您是否100%确定这个是瓶颈?

std::hash_set我想是

的方法