草庐IT

c++ - 执行 vector c++的交集

coder 2024-02-01 原文

我有 200 个大小从 1 到 4000000 的 vector 存储在 vecOfVec 中。我需要将这些 vector 与大小为 9000+ 元素的单个 vector “vecSearched”相交。我尝试使用以下代码来做同样的事情,但是使用 perf 工具我发现我正在做的交集是我代码中的瓶颈。有什么方法可以执行有效的交叉

#include <cstdlib>
#include <iostream>
#include <vector>

using namespace std;

int main(int argc, char** argv) {
  vector<vector<unsigned> > vecOfVec; //contains 120 vectors of size ranging from 1 to 2000000 elements. All vectors in vecOfVec are sorted
  vector<unsigned> vecSearched; //vector searched in contains 9000+ elements. Vectors in vecSearched are sorted
  for(unsigned kbt=0; kbt<vecOfVec.size(); kbt++)
  {                                  
     //first find first 9 values spaced at equi-distant places, use these 9 values for performing comparisons
     vector<unsigned> equiSpacedVec;                             

     if(((vecSearched[0]))>vecOfVec[kbt][(vecOfVec[kbt].size())-1]) //if beginning of searched vector > last value present in individual vectors of vecOfVec then continue
     {
         continue;                             
     }                         

     unsigned elementIndex=0; //used for iterating over equiSpacedVec                             
     unsigned i=0; //used for iterating over individual buckets vecOfVec[kbt].second
     //search for value in bucket and store it in bucketValPos
     bool firstRun=true;             
     for(vector<unsigned>::iterator itValPos=vecSearched.begin();itValPos!=vecSearched.end();++itValPos)
     {
         //construct a summarized vector out of individual vectors of vecOfVec
         if(firstRun)
         {
             firstRun=false;
             unsigned elementIndex1=0; //used for iterating over equiSpacedVec
             while(elementIndex1<(vecOfVec[kbt].size())) //create a small vector for skipping over the remaining vectors
             {
                  if((elementIndex1+(10000))<(vecOfVec[kbt].size()))
                     elementIndex1+=10000;
                  else
                     break;
                 equiSpacedVec.push_back(vecOfVec[kbt][elementIndex1]);
             }          
         }
         //skip individual vectors of vecOfVec using summarized vector constructed above
         while((!(equiSpacedVec.empty()))&&(equiSpacedVec.size()>(elementIndex+1))&&((*itValPos)>equiSpacedVec[elementIndex+1])){
             elementIndex+=1;
             if((i+100)<(vecOfVec[kbt].size()))
                 i+=100;
         }            
         unsigned j=i;
         while(((*itValPos)>vecOfVec[kbt][j])&&(j<vecOfVec[kbt].size())){
             j++;
         }
         if(j>(vecOfVec[kbt].size()-1)) //element not found even at last position.
         {
             break;
         }              

         if((*itValPos)==vecOfVec[kbt][j])
         {                                     
             //store intersection result
         }
     }
  }
    return 0;
}

最佳答案

您的问题很受欢迎。由于您没有相关 vector 相交的数据,它归结为加速两个 vector 之间的交集,基本上有两种方法:

1。无需任何预处理

这通常由三件事来解决:

  • 减少比较次数。例如,对于小 vector (大小为 1 到 50),您应该对每个元素进行二进制搜索,以避免遍历主题 vector 的所有 9000+ 个元素。

  • 提高代码质量以减少分支错误预测,例如,观察结果集通常比输入集的大小可以转换这样的代码:

    while (Apos < Aend && Bpos < Bend) {
        if (A[Apos] == B[Bpos]) {
            C[Cpos++] = A[Apos];
            Apos++; Bpos++;
        }
        else if (A[Apos] > B[Bpos]) {
            Bpos++;
        } 
        else {
          Apos++;
        } 
    }
    

    编写“展开”此类比较的代码,虽然更容易预测分支( block 大小 = 2 的示例):

    while (1) {
        Adat0 = A[Apos]; Adat1 = A[Apos + 1]; 
        Bdat0 = B[Bpos]; Bdat1 = B[Bpos + 1];
        if (Adat0 == Bdat0) { 
            C[Cpos++] = Adat0;
        }
        else if (Adat0 == Bdat1) {
            C[Cpos++] = Adat0;
            goto advanceB;
        }
        else if (Adat1 == Bdat0) {
            C[Cpos++] = Adat1;
            goto advanceA;
        }
        if (Adat1 == Bdat1) {
            C[Cpos++] = Adat1;
            goto advanceAB;
        }
        else if (Adat1 > Bdat1) goto advanceB;
        else goto advanceA;
    advanceA:
        Apos+=2;
        if (Apos >= Aend) { break; } else { continue; }
    advanceB:
        Bpos+=2;
        if (Bpos >= Bend) { break; } else { continue; }
    advanceAB:
        Apos+=2;  Bpos+=2;
        if (Apos >= Aend || Bpos >= Bend) { break; }
    }
    //  fall back to naive algorithm for remaining elements
    
  • 使用SIMD指令进行 block 操作

这些技术很难在 QA 上下文中描述,但您可以阅读它们(加上相关的优化,如 if 转换)herehere或查找实现元素 here

2。带预处理

恕我直言,这个方法更适合您的情况,因为您有一个大小为 9000 多个元素的单一主题 vector 。您可以从中制作一棵间隔树,或者简单地找到一种索引它的方法,例如制作一个可以加快搜索速度的结构:

vector<unsigned> subject(9000+); 
vector<range>    index(9000/M); 

其中 range 是一个类似的结构

struct range {
    unsigned min, max; 
}; 

这样就创建了一系列范围

[0, 100], [101, 857], ... [33221, 33500]

这将允许在进行交集时跳过许多比较(例如,如果另一个集合的元素大于子范围的最大值,您可以完全跳过该子范围)

3。并行化

是的,两个元素的列表中总有第三个元素 :P。当您对过程进行了足够的优化时(并且只有到那时),请将您的工作分解成 block 并并行运行。该问题符合令人尴尬的模式,因此 200 vector 对 1 应该明确地运行为“50 对 1 四次并发”

测试、测量、重新设计!!

关于c++ - 执行 vector c++的交集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31065273/

有关c++ - 执行 vector c++的交集的更多相关文章

  1. ruby-openid:执行发现时未设置@socket - 2

    我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - Chef 执行非顺序配方 - 2

    我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul

  4. ruby - 为什么 Ruby 的 each 迭代器先执行? - 2

    我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试

  5. ruby - 检查是否通过 require 执行或导入了 Ruby 程序 - 2

    如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby​​文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否

  6. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  7. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  8. ruby-on-rails - rbenv:从 RVM 移动到 rbenv 后,在 Jenkins 执行 shell 中找不到命令 - 2

    我从Ubuntu服务器上的RVM转移到rbenv。当我使用RVM时,使用bundle没有问题。转移到rbenv后,我在Jenkins的执行shell中收到“找不到命令”错误。我内爆并删除了RVM,并从~/.bashrc'中删除了所有与RVM相关的行。使用后我仍然收到此错误:rvmimploderm~/.rvm-rfrm~/.rvmrcgeminstallbundlerecho'exportPATH="$HOME/.rbenv/bin:$PATH"'>>~/.bashrcecho'eval"$(rbenvinit-)"'>>~/.bashrc.~/.bashrcrbenvversions

  9. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  10. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

随机推荐