比较两个包含字符串的向量的快速方法

时间:2018-10-02 15:57:50

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

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

以下代码段显示了我需要做的事情(这是我的工作方式,但是最快的方法是什么):

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;
}

Edit1

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

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

6 个答案:

答案 0 :(得分:2)

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

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;
}

答案 1 :(得分:1)

您的方法的缺点是它的线性。您想对Speedz进行二进制搜索。

通过利用map的排序,在其中查找的二元性以及vector之间的等效性,已经为您定义了事实(不需要第一个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;
}

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

(我尚未针对确切的语法正确性进行过测试,但您明白了。)

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

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


要回答您的后续问题:您需要指定类型:

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

但是,如上文所述,让std::map::find替您执行此操作。更好。

答案 2 :(得分:0)

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

因此,它变成:

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_viewlook 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

答案 3 :(得分:0)

如果您想要一种快速的方法来进行比较,而事先不知道要比较的向量,但是可以重复使用这些向量,从而可以节省一些初始运行时开销,则可以构建类似于编译时版本的树结构德克·赫尔曼(Dirk Herrmann)有。只需遍历输入并遵循树,即可在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

答案 4 :(得分:-1)

您可以使用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())
}

答案 5 :(得分:-1)

  

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

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

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 )

所以:

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