【问题标题】:Fast algorithm for string/(vector of strings) matching字符串/(字符串向量)匹配的快速算法
【发布时间】:2021-01-17 20:16:13
【问题描述】:

所以我有一个正好有 5 个字符串的 向量 V1。

我有一组向量(称为过滤器)(每个都有 5 个字符串)。

我需要一个快速算法,以便我可以查看给定向量是否与集合中的任何向量匹配。

向量 V1 对集合中的一个向量进行数学运算(例如 filter1)如果

V1[i] = filter1[i] OR filter[i] = ""(空字符串)

例子:

过滤器:

filter1: "abc" "bcd" "bb" "" ""

过滤器2:“abc”“bcd”“bb”“ee”“ff”

filter3: "abc" "ddd" "bb" "j" ""

搜索到的向量:

V1:“abc”、“bcd”、“bb”、“ee”、“ff”

V1 匹配过滤器中的两个向量:filter1filter2

所以我正在考虑将过滤器存储在 unordered_set 中。但我不知道如何制作散列函数,所以它可以找到一个匹配项(它会为不同的向量提供不同的散列值(即使它们可以匹配)。我的另一个想法是构造一个正则表达式。但再次搜索将是 O(n)。 任何提示如何检查 O(log(n))O(1)(其中 n 是过滤器向量的大小)的匹配?

【问题讨论】:

  • std::regex 匹配可能会在更大数量的 og 输入数据上为您提供最佳性能。

标签: c++ algorithm data-structures hashmap unordered-set


【解决方案1】:

尚不清楚您想要的所有行为和约束是什么。例如,按照您列出的示例过滤器从左到右的顺序,过滤器是否可以包含“”(您的匹配所有“通配符”),然后是另一个非“”字符串?

无论如何,假设您不允许允许过滤器有一个"" 通配符后跟一个非"" 术语,您可以创建一个类型为...的过滤器索引...

std::unordered_map<std::string,
  std::variant<filter*,
    std::unordered_map<std::string,
      std::variant<filter*,
        std::unordered_map<std::string,
          std::variant<filter*,
            std::unordered_map<std::string,
              std::variant<filter*,
                std::unordered_map<std::string, filter*>
> > > > > > > > index;

这有效地描述了一个树,其中每个级别可能有一个精确的字符串匹配或一个"" 通配符过滤器匹配,如果这是过滤器中最后一个非"" 术语,则为匹配的过滤器产生一个filter* ,或索引的下一级。

鉴于您的过滤候选对象v1,并假设您已经完成了填充索引的明显工作,您可以像这样进行搜索:

std::vector<filter*>
match(const std::array<string, 5>& v,
      const auto& index) {
    std::vector<filter*> matches;

    auto it0 = index.find("");
    if (it0 != index.end())
         matches.push_back(std::get<filter*>(*it0)); // match-everything filter
    if ((it0 = index.find(v[0])) == index.end())
        return matches; // no non-wildcard match

    const auto& i1 = std::get<1>(*it0); // next level in index
    auto it1 = i1.find("");
    ...same kind of logic, working your way through the 5 levels...

这涉及最多 10 个哈希表查找,因此 O(1) w.r.t。过滤器集的大小。

这并不一定意味着它是任何给定数据的最佳性能选择:字符串的典型长度、其中的模式,例如可能以相同的字符开头并且仅在最后一个不同几个字符,过滤器集的长度 - 了解这些内容可能会建议一种实际上更快的方法。

哈希表的工作情况还取决于所使用的哈希函数。对于较长的字符串,GCC 的字符串哈希函数 - MURMUR32 - 比 Visual C++ 的质量要高得多(为了提高速度,它只包含沿字符串间隔的 10 个字符),并且 GCC 使用质数桶计数,这比 Visual C++ 的功能更不容易发生冲突 - of-2 选择。其他优化可以通过对数据的了解来建议,例如如果您知道字符串总是

【讨论】:

  • 如果我理解正确,那么您需要一个完美的哈希函数来保证在哈希映射中查找 O(1) 或者我在这里忽略了一些东西。
  • @Surt:是的,你忽略了一些东西——即 O(1) 的含义。检查“链接列表长度与负载因子有关,而不是值的数量”下的this answer,如果你这样做没有帮助,我会在这里或那里欢迎另一个问题。
  • 如果我在最坏的情况下查看hash table,我会看到 O(N)。
  • @Surt:是的,但是如果你使用一个强大的哈希函数,你会得到几百个或更多元素,发生这种情况的概率远低于你的计算机被流星击中的概率在它完成查找之前,因此可以非常合理地忽略。但是,您确实需要知道如何编写或选择适当的哈希函数,并处理与您的场景相关的故意对抗密钥生成(例如,具有开源代码的网站,有人可以看到您的哈希函数和工程师碰撞密钥)。
猜你喜欢
  • 1970-01-01
  • 2012-07-24
  • 2015-06-22
  • 1970-01-01
  • 1970-01-01
  • 2011-01-19
  • 2013-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多