【问题标题】:C++ Search PerformanceC++ 搜索性能
【发布时间】:2011-08-30 02:08:38
【问题描述】:

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

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

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))       
         veccomp.push_back(s);  

     while (getline(miscfile,t))        
         vectenk.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 # of lines in misc text file)迭代。如果有人可以提供帮助,我当然会很感激。一些示例代码是最受欢迎的。此外,如果这有什么不同,我正在使用 Dev C++。谢谢。

【问题讨论】:

    标签: c++ performance string full-text-search


    【解决方案1】:

    使用std::hash_set。将所有关键词插入到集合中,然后遍历大文档,每次遇到一个词,测试集合中是否包含该词。

    【讨论】:

    • std::unordered_map 更符合标准。对于更花哨的东西,考虑实现一个布隆过滤器(不平凡)。
    • 看起来 unordered_map 是 C++0x 的东西...我会把赌注押在 hash_map 上,它存在于 gcc 的 libstdc++ 和 MSVC 中。
    • bloom 过滤器很简洁,但当搜索集是 70K 条目时,并不是特别需要。特别是,消除误报不太可能比适应比 1.5 MB 更小的内存占用更可取。
    • 你会把赌注押在非标准的东西上而不是标准的东西上? MSVC 和 GCC 都附带 unordered_map
    【解决方案2】:

    使用向量,您将获得的最佳情况搜索时间是使用二进制搜索算法的 O(log N) 复杂度,并且这只适用于排序列表。如果将排序插入到列表中所需的时间包括在内,则排序线性容器(数组、列表)以及非线性容器(例如二叉搜索树)的最终摊销复杂度,O(N log N )。所以这基本上意味着如果你向列表中添加更多元素,将这些元素添加到列表中以及稍后找到它们所花费的时间将以比线性增长率略快的速度增加列表(即,如果您将列表的大小加倍,则对列表进行排序将花费两倍多的时间,然后列表上的任何搜索都会非常快......为了使搜索时间加倍,该列表必须按现有元素数量的平方增长)。

    另一方面,一个好的哈希表实现(例如std::unordered_map)以及一个避免太多冲突的好的哈希算法,具有 O(1) 的摊销复杂度......这意味着总体上有无论有多少元素,任何给定元素的查找时间都是恒定的,这使得搜索速度非常快。散列表的线性列表或二叉搜索树的主要损失是散列表的实际内存占用。一个好的哈希表,为了避免太多的冲突,需要一个大小等于某个至少大于 2*N 的大素数,其中 N 是您计划存储在大批。但是“浪费的空间”是高效和极快查找的权衡。

    【讨论】:

      【解决方案3】:

      虽然任何类型的地图都是最简单的解决方案,但 Scott Myers 为排序 vectoralgorithm 中的 binary_search 提供了一个很好的案例(在 Effective STL 中)。

      使用排序向量,您的代码将类似于

      #include <algorithm>
      

      ...

      int vecsize = vecnames.size();
      sort(vecnames.begin(), vecnames.begin() + vecsize );
      for (vector<string>::size_type j = 0;j != vecmisc.size(); ++j)
      {
        bool found= binary_search(vecnames.begin(), vecnames.begin()+vecsize,vecmisc[j]);
        if (found) std::cout << vecmisc[j] << std::endl;
      }
      

      使用排序向量和 binary_search 的优点是

      1) 没有要遍历的树,binary_search 从 (end-start)/2 开始,一直除以 2。最多需要 log(n) 来搜索范围。

      2) 没有键值对。无需地图开销即可获得矢量的简单性。

      3) 向量的元素在一个连续的范围内(这就是为什么您应该在填充向量之前使用保留,插入更快),因此搜索向量的元素很少跨越页面边界(稍微快一点)。

      4) 很酷。

      【讨论】:

        猜你喜欢
        • 2012-03-19
        • 1970-01-01
        • 2018-12-10
        • 1970-01-01
        • 1970-01-01
        • 2018-11-22
        • 2019-07-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多