使用 C++ 的排序对引用的子字符串进行排序?

Posted

技术标签:

【中文标题】使用 C++ 的排序对引用的子字符串进行排序?【英文标题】:Sorting referenced substrings using C++'s sort? 【发布时间】:2018-01-08 01:51:45 【问题描述】:

我有两个长字符串(大约一百万个字符),我想从中生成后缀并进行排序,以便找到最长的共享子字符串,因为这比暴力破解所有可能的子字符串要快得多。我最熟悉 Python,但我的快速计算估计有 40 Tb 的后缀,所以我希望可以使用 C++(建议)对每个主要的、不变的字符串中的子字符串的引用进行排序。

我需要保留每个子字符串的索引,以便稍后找到值和原始字符串,因此任何关于我可以使用的数据结构类型的建议都将 1)允许对引用字符串进行排序和 2)跟踪原始索引将非常有帮助!

当前伪代码:

//Function to make vector? of structures that contain the reference to the string and the original index
int main() 

//Declare strings
string str1="This is a very long string with some repeats of strings."
string str2="This is another string with some repeats that is very long."

//Call function to make array

//Pass vector to sort(v.begin(), v.end), somehow telling it to deference?

//Process the output in multilayer loop to find the longest exact match
// "string with some repeats"

return 0;

【问题讨论】:

2.为索引和字符串长度创建一个元组列表(char* idx, int len) 有了这些尺寸,我很想使用数据库。 我们正在实施 BWT(Burrows Wheeler 变换)吗?如果是这样,请不要使用std::string - 使用char * 【参考方案1】:

首先,您应该为此使用后缀树。但我会回答你原来的问题。

C++17:

注意:使用实验性功能

您可以使用std::string_view 来引用字符串而无需复制。这是一个示例代码:

//Declare string
char* str1 = "This is a very long string with some repeats of strings."

int main() 

    //Call function to make array
    vector<string_view> substrings;

    //example of adding substring [5,19) into vector
    substrings.push_back(string_view(str1 + 5, 19 - 5));

    //Pass vector to sort(v.begin(), v.end)
    sort(substrings.begin(), substrings.end());

    return 0;

C++17 之前的一切:

您可以使用带有sort 函数的自定义谓词。不要让你的向量存储实际的字符串,而是让它存储包含索引的对。

以下是使其工作所需的代码示例:

//Declare string
string str1="This is a very long string with some repeats of strings."

bool pred(pair<int,int> a, pair<int,int> b)
    int substring1start=a.first,
        substring1end=a.second;
    int substring2start=b.first,
        substring2end=b.second;

    //use a for loop to manually compare substring1 and substring 2
    ...

    //return true if substring1 should go before substring2 in vector
    //otherwise return false


int main() 
    //Call function to make array
    vector<pair<int,int>> substrings;

    //example of adding substring [1,19) into vector
    substrings.push_back(1,19);

    //Pass vector to sort(v.begin(), v.end), passing custom predicate
    sort(substrings.begin(), substrings.end(), pred);

    return 0;

即使您减少内存使用量,您的程序仍然需要 40T 迭代才能运行(因为您需要比较字符串)。除非你使用某种哈希字符串比较算法。

【讨论】:

包含 string_view、整数位置和其他所需信息的结构向量正是我需要的目的。感谢您建议 string_views;很高兴这是对 C++17 的补充。【参考方案2】:

您可以使用std::string_viewstd::hashstd::set 的组合。

#include <iostream>
#include <set>
#include <string>
#include <string_view>
#include <vector>

std::string str1="This is a very long string with some repeats of strings.";
std::string str2="This is another string with some repeats that is very long.";

std::set<std::size_t> substringhashes;
std::vector<std::string_view> matches;

bool makeSubHashes(std::string& str, std::size_t lenght) 
    for (int pos=0; pos+lenght <= str.size(); ++pos) 
        std::string_view sv(str.data()+pos, lenght);
        auto hash = std::hash<std::string_view>()(sv);
        if (!substringhashes.insert(hash).second) 
            matches.push_back(sv);
            if (matches.size() > 99) // Optional break after finding the 100 longest matches
                return true;
        
    
    return false;


int main() 
    for (int lenght=std::min(str1.size(), str2.size()); lenght>0; --lenght) 
        if (makeSubHashes(str1, lenght) || makeSubHashes(str2, lenght))
            break;
    

    for (auto& sv : matches) 
        std::cout << sv << std::endl;
    
    return 0;

如果后缀数量非常多,std::set 可能会出现误报。它有std::size_ts 不同哈希的最大值数,通常是uint64

它还开始在字符串的最大长度处搜索匹配项,也许更合理的方法是为后缀设置某种最大长度。

【讨论】:

【参考方案3】:

std::sort 对主内存中的数据进行排序。

如果您可以将数据放入主内存中,则可以使用std::sort对其进行排序。

否则不会。

【讨论】:

以上是关于使用 C++ 的排序对引用的子字符串进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

在 django 中按模型字段的子字符串对对象进行排序

C++:使用 LSD 基数排序对字符串进行排序崩溃

对 C++ 字符串的字符进行排序

用于对字符串进行排序的 C++ sort() 函数

排序算法的c++实现——归并排序

在 C++ 中使用链表按字母顺序对字符串进行排序