C ++有效地获取带有索引的字符串的子字符串

c++ efficiently get substring of string with index

本文关键字:字符串 索引 有效地 获取      更新时间:2023-10-16

在我的项目中,我必须从 index=0 开始迭代一个大字符串并获取长度 k 子字符串。我已经实现了string::substr(),想知道是否有其他有效的方法。

例如:

std::string S ="ABCDEFGHIJKLMN"

我需要从 S 的开头获取长度 = 5 的所有子字符串,就像"ABCDE""BCDEF""CDEFG"等等。

我的实现如下所示:

void geekfunc(std::string &str)
{
unsigned int index=0;
for (; index<=(str.size()-K);++index)
{
++myseqmap[str.substr(index,K)];
}
}

这个函数被调用了一千万次,我欢迎其他方法尝试。

如果您使用的是 C++17,则可以使用string_view作为参数和映射键类型。这样,您就不会在每次调用substr时都复制字符串内容。只需确保您传递给函数的字符串在地图仍在使用时不会被破坏或修改即可。

std::map<std::string_view, std::size_t> myseqmap;
void geekfunc(std::string_view str)
{
unsigned int index=0;
for (; index<=(str.size()-K);++index)
{
++myseqmap[str.substr(index,K)];
}
}

如果您确实需要创建子字符串的副本(string::substr 确实需要创建),我相信您无法通过对内存管理器的调用少于Omega(m)次并总共Omega(m * k)复制步骤来解决此问题,其中m = n - k + 1.这是因为该标准要求每个字符串管理自己的内存。不允许共享(例如使用写入时复制习惯用法),因此每个子字符串将从原始字符串复制其内容。

如果不需要副本,并且编译器已经提供了 std::string_view,您可以尝试使用它。与string不同,string_view只包含一个指向字符和大小的指针(这正是您创建子字符串的指针)。可以使用 string::d ata 获取所需的指针。

但是,使用string_view时,必须确保原始字符串在包含子字符串的容器中保留在范围内,并且在创建子字符串后不会更改,因为这可能会使string_view持有的指针无效。这些问题可以通过像这样将类中的所有内容包装在一起来解决:

struct substrings{
const std::string original;
container<string_view> substrings;
};

container是您选择的任何容器。

您正在搜索任何给定字符串的 K-mers。

static vector<string> find_kmers(string Text, int k)
{
vector<string> kmers;
int n = Text.length();;
for (int i = 0; i < n-k+1; i++)
kmers.push_back(Text.substr(i, k));               
return kmers;
}