在 C++11 中,如何查找并返回以给定字符串开头的字符串向量中的所有项?

In C++11, how to find and return all the item(s) in a vector of strings that start with a given string?

本文关键字:字符串 开头 向量 返回 何查找 C++11 查找      更新时间:2023-10-16

(注意:当我提到向量时,我指的是<vector>提供的vector类。

问题所在

给定一个字符串x和一个字符串向量,如何检索向量中以x开头的字符串?最好以省时的方式?

也就是说,如果x"apple"并且向量是vector<string> foods = {"apple pie","blueberry tarts","cherry cobbler"}的,那么它应该以某种身份返回"apple pie"

我正在使用C++11,但我不是这方面的专家,所以简单的答案和解释将不胜感激。如果答案很明显,请原谅我 - 我对这门语言相对较新。

我考虑过的可能解决方案

显而易见的解决方案是创建一个迭代器并遍历向量中的每个字符串,使用具有pos参数的重载版本的rfind提取以给定字符串开头的所有项目。(也就是说,像这样:str.rfind("start",0)(

但是,对于大向量,这在时间上效率低下,所以我想知道是否有更好的方法来做到这一点,即对向量进行排序并使用某种二叉搜索,或者也许从<algorithm>修改find方法?

复制所需字符串的最简单方法是简单的线性扫描。例如,使用标准库std::copy_if执行复制,并使用 lambda 封装"开头为"字符串比较。

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> foods = { "apple pie","blueberry tarts","cherry cobbler" };
std::string prefix{ "apple" };
auto starts_with = [&prefix](const std::string &str) {
return str.compare(0, prefix.size(), prefix) == 0;
};
std::vector<std::string> result;
std::copy_if(begin(foods), end(foods), back_inserter(result), starts_with);
for (const auto &str : result) {
std::cout << str << 'n';
}
}

解决问题的一个好方法是使用二叉搜索。请注意,这需要首先对stringsvector进行排序,这使算法的时间复杂度为NlogN


vector <string> v = {"a", "apple b", "apple c", "d"}; // stuff
string find = "apple";
// create a second vector that contains the substrings of the first vector
vector <pair<string, string>> v2;
for(string item : v){
v2.push_back({item.substr(0, find.size()), item});
}
sort(v2.begin(), v2.end());
// binary search to find the leftmost and rightmost occurrence of find
int l = v.size()-1, r = 0;
for(int i = v.size()/2; i >= 1; i /= 2){
while(l-i >= 0 && v2[l-i].first >= find){l -= i;}
while(r+i < v.size() && v2[r+i].first <= find){r += i;}
}
if(v2[l].first == find){
for(int i = l; i <= r; ++i){
cout << v2[i].second << endl;
}
}
else{
cout << "No matches were found." << endl;
}

在我的代码中,我们首先创建一个名为v2的第二个vector来存储strings对。排序后,我们通过跳转实现二叉搜索,以找到find的最左边和最右边的出现次数。最后,我们检查是否有任何出现(这是一个边缘情况(,并打印所有找到的strings如果存在

您可以在向量上的单次传递中执行此操作。 除非对向量进行预排序,否则这是您最好的方法,因为排序的成本将超过使用二叉搜索获得的任何收益。

使用std::copy_if使这变得非常简单:

#include <string>
#include <vector>
#include <algorithm>
int main() {
std::vector<std::string> v = {
"apple pie",
"blueberry tarts",
"apple",
"cherry cobbler",
"pie"
};

std::vector<std::string> v2;
std::string to_find = "apple";
std::copy_if(
v.begin(),
v.end(),
std::back_inserter(v2),
[&to_find](const std::string& el) {
return el.compare(0, to_find.size(), to_find) == 0;
}
);
}

现场演示

这会将v中与谓词函数匹配的所有元素复制到v2中。 谓词只是检查每个元素的前to_find.size()个字符是否与要使用std::string::compare查找的字符串匹配(该页面上的重载 (2((。