【问题标题】:fast way to compare two vector containing strings比较两个包含字符串的向量的快速方法
【发布时间】:2019-03-07 19:16:29
【问题描述】:

我有一个字符串向量传递给我的函数,我需要将它与一些预定义的值进行比较。最快的方法是什么?

下面的代码 sn-p 显示了我需要做什么(这是我的做法,但最快的方法是什么):

bool compare(vector<string> input1,vector<string> input2)
{
   if(input1.size() != input2.size()
   {
      return false;
   }
   for(int i=0;i<input1.siz();i++)
   {
       if(input1[i] != input2[i])
       {
            return false;
       }
   }
   return true; 

}
int compare(vector<string> inputData)
{
     if (compare(inputData,{"Apple","Orange","three"}))
     {
          return 129;
     }
     if (compare(inputData,{"A","B","CCC"}))
     {
          return 189;
     }
     if (compare(inputData,{"s","O","quick"}))
     {
          return 126;
     }
     if (compare(inputData,{"Apple","O123","three","four","five","six"}))
     {
          return 876;
     }
     if (compare(inputData,{"Apple","iuyt","asde","qwe","asdr"}))
     {
          return 234;
     }
     return 0;
}

编辑1

我可以像这样比较两个向量吗:

 if(inputData=={"Apple","Orange","three"})
 {
     return 129;
 }

【问题讨论】:

  • std::vector 已经有operator==。无需自己编写。
  • 第一。通过 const 引用而不是通过复制传递参数
  • 嗯,return vector1 == vector2;?
  • 您可以将已知向量字符串映射到结果 int。
  • @FrançoisAndrieux 你能详细说明一下吗?

标签: c++ c++11 vector std


【解决方案1】:

您在问什么是最快的方法来做到这一点,并且您表示您正在与一组固定且已知的字符串进行比较。我认为您可能必须将其实现为一种状态机。并不是说这很漂亮……

if (inputData.size() != 3) return 0;
if (inputData[0].size() == 0) return 0;
const char inputData_0_0 = inputData[0][0];
if (inputData_0_0 == 'A') {
   // possibly "Apple" or "A"
   ...
} else if (inputData_0_0 == 's') {
   // possibly "s"
   ...
} else {
   return 0;
}

【讨论】:

  • 我也在考虑同样的思路,并寻找一些关于快速词法分析器/扫描仪的信息,例如这里nothings.org/computer/lexing.html
  • 您可以很容易地为这类状态机生成代码,但是对于大量情况我不会手动编写。这样的状态机在输入上是O(n) 最坏情况(匹配),没有内存分配,所以不要相信它可以被打败。
  • 也可以在运行时动态生成类似的树形结构。
【解决方案2】:

你的方法的弱点是它的线性。您想要对 speedz 进行二分搜索。

通过利用 map 的排序性、在一个中查找的二进制性以及 vectors 之间的等价性已经为您定义(不需要第一个 compare 函数!),您可以很容易做到这一点:

std::map<std::vector<std::string>, int> lookup{
   {{"Apple","Orange","three"}, 129},
   {{"A","B","CCC"}, 189},
   // ...
};

int compare(const std::vector<std::string>& inputData)
{
    auto it = lookup.find(inputData);
    if (it != lookup.end())
       return it->second;
    else
       return 0;
}

还要注意额外速度的参考传递。

(我还没有测试过它的语法正确性,但你明白了。)

但是! 与往常一样,我们需要在设计中了解上下文。这种方法在更大范围内更有用。目前你只有几个选项,所以添加一些动态分配和排序以及所有这些爵士乐实际上可能会减慢速度。最终,您将希望采用我的解决方案和您的解决方案,并衡量结果典型输入等等。

完成此操作后,如果由于某种原因仍需要更高的速度,请考虑寻找减少向量和字符串本身固有的动态分配的方法。


回答您的后续问题:几乎;您确实需要指定类型:

//                   new code is here
//               ||||||||||||||||||||||||
if (inputData == std::vector<std::string>{"Apple","Orange","three"})
{
   return 129;
}

不过,正如上面所探讨的,让std::map::find 代替您执行此操作。它更胜一筹。

【讨论】:

  • 我猜在你的地图中 key 应该是 int 而不是 vector
  • 顺便说一句,输入大小为 (5),IMO 的瓶颈不是线性与对数搜索的复杂性。 Trie 可能很有趣。
  • @Maddy 为什么?该界面似乎是 of 一个 int by 向量的查找。
  • @Jarod42 嗯,这实际上是一个公平的观点。在这个规模上,我的整个建议有点愚蠢^_^
  • 速度如此之快!
【解决方案3】:

效率的一个关键是消除不必要的分配。

因此,它变成:

bool compare(
    std::vector<std::string> const& a,
    std::initializer_list<const char*> b
) noexcept {
    return std::equal(begin(a), end(a), begin(b), end(b));
}

或者,将它们设为static const,并接受轻微的开销。

顺便说一句,使用 C++17 std::string_view (look at boost)、C++20 std::span(查找 Guideline support library (GSL))也可以提供更好的选择:

bool compare(std::span<std::string> a, std::span<std::string_view> b) noexcept {
    return a == b;
}

另一个是最小化比较次数。您可以使用散列、二分查找或手动比较排序。

不幸的是,透明比较器是 C++14 的东西,所以你不能使用 std::map

【讨论】:

  • @Jarod42 消除了这一点,甚至不需要去 C++11 标准库之外。
【解决方案4】:

如果您想要一种快速的方法来做到这一点,其中要比较的向量事先不知道,但可以重复使用,因此可能会有一点初始运行时开销,您可以构建一个类似于编译时版本的树形结构德克赫尔曼有。这将在O(n) 中运行,只需遍历输入并跟随一棵树。

在最简单的情况下,您可以为每个字母/元素构建一棵树。部分实现可能是:

typedef std::vector<std::string> Vector;
typedef Vector::const_iterator Iterator;
typedef std::string::const_iterator StrIterator;
struct Node
{
    std::unique_ptr<Node> children[256];
    std::unique_ptr<Node> new_str_child;
    int result;
    bool is_result;
};

Node root;
int compare(Iterator vec_it, Iterator vec_end, StrIterator str_it, StrIterator str_end, const Node *node);
int compare(const Vector &input)
{
    return compare(input.begin(), input.end(), input.front().begin(), input.front().end(), &root);
}
int compare(Iterator vec_it, Iterator vec_end, StrIterator str_it, StrIterator str_end, const Node *node)
{
    if (str_it != str_end)
    {
        // Check next character
        auto next_child = node->children[(unsigned char)*str_it].get();
        if (next_child)
            return compare(vec_it, vec_end, str_it + 1, str_end, next_child);
        else return -1; // No string matched
    }
    // At end of input string
    ++vec_it;
    if (vec_it != vec_end)
    {
        auto next_child = node->new_str_child.get();
        if (next_child)
            return compare(vec_it, vec_end, vec_it->begin(), vec_it->end(), next_child);
        else return -1; // Have another string, but not in tree
    }
    // At end of input vector
    if (node->is_result)
        return node->result; // Got a match
    else return -1; // Run out of input, but all possible matches were longer
}

这也可以在没有递归的情况下完成。对于像您这样的用例,您会发现大多数节点只有一个成功值,因此您可以将它们折叠成前缀子字符串,以使用 OP 示例:

"A"
 |-"pple" - new vector - "O" - "range" - new vector - "three" - ret 129
 |                    |- "i" - "uyt"   - new vector - "asde" ... - ret 234
 |                    |- "0" - "123"   - new vector - "three" ... - ret 876
 |- new vector "B" - new vector - "CCC" - ret 189
"s" - new vector "O" - new vector "quick" - ret 126

【讨论】:

    【解决方案5】:

    您可以使用 std::equal 函数,如下所示:

    bool compare(vector<string> input1,vector<string> input2)
    {
       if(input1.size() != input2.size()
       {
          return false;
       }
    
       return std::equal(input1.begin(), input2.end(), input2.begin())
    }
    

    【讨论】:

    • 这解决了错误的问题;您正在解决的问题的解决方案是==,它已经存在。
    【解决方案6】:

    我可以像这样比较两个向量吗

    答案是否定的,您需要将一个向量与另一个向量进行比较,如下所示:

    vector<string>data = {"ab", "cd", "ef"};
    
    if(data == vector<string>{"ab", "cd", "efg"})
        cout << "Equal" << endl;
    else
        cout << "Not Equal" << endl;
    

    最快的方法是什么?

    我不是渐近分析专家,但是:

    使用关系运算符相等性 (==),您有一个比较两个向量的快捷方式,首先验证大小,然后验证它们上的每个元素。这种方式提供了一个线性执行(T(n),其中 n 是向量的大小),它比较向量的每个项目,但必须比较每个字符串,并且,通常,它是另一个线性比较(T(m),其中 m 是字符串的大小)。

    假设每个字符串具有相同的大小 (m),并且您有一个大小为 n 的向量,每次比较的行为可能为 T(nm )

    所以:

    • 如果你想要一个比较两个向量的快捷方式,你可以使用 关系运算符相等
    • 如果您想要一个执行快速比较的程序,您应该寻找一些比较字符串的算法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-11
      • 2019-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多