C++搜索性能

C++ Search Performance

本文关键字:性能 搜索 C++      更新时间:2023-10-16

可能重复:
C++搜索性能

我有两个文本文件。其中一个包含大约70000个名字(约1.5MB)的列表。另一个包含将从其他来源获得的文本。也就是说,每次执行程序时,这个文件的内容都会发生变化(~0.5MB)。本质上,我希望能够将一些文本粘贴到文本文件中,看看我的列表中有哪些名称。有点像查找功能(CTR+F),但有70000个关键字。

无论如何,到目前为止,我所拥有的是:

 int main()
 {
 ifstream namesfile("names.txt");   //names list
 ifstream miscfile("misc.txt");     //misc text
 vector<string> vecnames;           //vector to hold names
 vector<string> vecmisc;            //vector to hold misc text
 size_t found;
 string s;
 string t;
 while (getline(namesfile,s))       
     vecnames.push_back(s);  
 while (getline(miscfile,t))        
     vecmisc.push_back(t);
 //outer loop iterates through names list
 for (vector<string>::size_type i = 0; i != vecnames.size(); ++i) {
     //inner loop iterates through the lines of the mist text file
     for (vector<string>::size_type j = 0;j != vecmisc.size(); ++j) {
         found=vecmisc[j].find(vecnames[i]);
         if (found!=string::npos) {
             cout << vecnames[i] << endl;
             break;
         }
     }
 }
 cout << "SEARCH COMPLETE";
 //to keep console application from exiting
 getchar();
 return 0;
 }

现在,就提取我需要的数据而言,这非常有效,然而,它非常慢,而且显然效率低下,因为每个名称都需要我再次搜索整个文件,这会产生(混合文本文件中的75000 x#行)迭代。如果有人能帮忙,我当然会很感激。一些示例代码是最受欢迎的。此外,如果有什么不同的话,我会使用Dev C++。

有人建议我在数据上实现一个哈希集,然而,我不知道如何实现。如果有人了解我如何应用这种方法,我会很感激能朝着正确的方向开始。衷心感谢。

您可以从所有名称构造一个trie,并标记作为端点的节点,这样您就可以知道何时匹配(或者您可以等待不匹配,并从最后一个匹配结束时发出子字符串)。然后尝试将输入匹配到trie,一次一个字符,您应该具有O(n)性能。

trieRoot = preprocessedListOfNames
trieCursor = trieRoot
for each character in text
    if character in trieCursor.neighbors
        trieCursor = trieCursor.neighbors[character]
    else
        if matchSize > 1 and trieCursor.isEndpoint
            emit match
        trieCursor = trieRoot

如果名称列表相对静态,您甚至可以对其进行预处理并存储,这样您就不必每次进行搜索时都构建它。

vecnames从向量更改为集合。将其调用更改为push_back以插入。然后,不在上面循环,只在vecmisc上循环并调用vecnames.find(...)来检查每个输入是否是其中一个名称。这将把你的O(n m)系统变成O(n log m)。您还可以使用hash_set并实现O(n)(在实践中可能快得多,也可能快得不多)。

您最好将较大的文件读入内存;qsort()正在处理它;然后逐行读取第二个文件,并对该第二文件中的每个条目执行bsearch()操作。

您可以使用STL中的映射/关联数组数据结构。映射不一定以线性方式存储数据,因此查找操作通常花费少于线性时间(即-<O(n)。

对于您的情况,您可以使用类型为map<string,bool>的映射。示例用法-http://www.cprogramming.com/tutorial/stl/stlmap.html

vector<string> vecmisc;替换为map<string,bool> vecmisc

for (vector<string>::size_type i = 0; i != vecnames.size(); ++i) {
 // No inner loop needed
     found=vecmisc.find(vecnames[i]);
     if (found!=string::npos) {
         cout << vecnames[i] << endl;
         break;
     }
 }

一些细微的改进。

之前的基准:7分56秒,正在计数(将更新)更新:最终在15m25s内完成,的性能提高了约3000 x

基准之后:0.3?秒(更新数据见下文)

代码:

#include <set>
#include <string>
#include <iostream>
#include <iterator>
#include <fstream>
template <class It> It readInto(std::istream& is, It OI);
std::set<std::string> readnames(const std::string& filename)
{
    std::string s;
    std::set<std::string> result;
    std::ifstream namesfile(filename.c_str());   //names list
    readInto(namesfile, std::inserter(result, result.end()));
    return result;
}
int main()
{
    std::set<std::string> vecnames = readnames("names.txt");
    //inner loop iterates through the lines of the mist text file
    std::ifstream miscfile("misc.txt");     //misc text
    std::string line;
    while (std::getline(miscfile, line))
        if (vecnames.end() != vecnames.find(line))
            std::cout << line << std::endl;
    return 0;
}
// helper to read linewise into output iterator
template <class It> It readInto(std::istream& is, It OI)
{
    std::string line;
    while (std::getline(is, line))
    {
        if (line.size()>0) // TODO you may want to trim/normalize these
            OI++ = line;
    }
    return OI;
}

数据:

$cp/etc/dictions-common/words-names.txt$$wc names.txt misc.txt98569 98568 931708 names.txt166634 529910 4283592 miss.txt

这导致151486行输出(检查时包含3968个唯一值:)

$ ./t2 | wc -l
859
$ ./t2 | sort -u | wc -l
2

因为这是一个非常扭曲的基准,我也对另一个极端进行了基准测试:

$ cp names.txt misc.txt
$ time ./t | wc -l
98568
real    0m0.365s
user    0m0.372s
sys 0m0.228s

在i386(32位)g++4.4.5上使用优化构建执行的测试,将stdout重定向到/dev/null,并在结束时删除getchar()调用