2016-02-13 72 views
0

我想比较用整数填充的向量的元素,以查看具有相同值(并对它们进行计数)的元素是否为 。快速向量元素比较

因此,例如,如果a[i]==x,有没有b[j]==x

浮现在脑海的第一个实现,当然是最简单的一个:

for (int i=0; i < a.size(); i++) { 
    for (int j=0; j < b.size(); j++) { 
    if (a[i]==b[j]) {counter++;} 
    } 

这是这样的大载体放缓。 我曾经想过交替算法,但我对不熟练的实施 是正确的,所以在这里它是,我有又和我的问题:

for (int i = 0; i < n; i++) { 
    for (int j = 0; j < m; j++) { 
     if (b[j] >= a[i]) { 
     counter++; 
     for (int k = i + 1; k < n; k++) { 
      if (a[k] >= b[j+1]) { 
      counter++; 
      for (int l = k + 1; l < m; l++) { 
       if (b[l] >= a[k]) { 
       counter++; 
       .... 
       } 
      } 
      } 
     } 
     } 
    } 
    } 

流程是,我开始比较a的第一个元素与b的元素。当我点击时,我跳转到矢量b,并将其下一个元素与a的元素进行比较,该元素位于a元素之后,与之前进行比较。 (由于ab的元素存储在升序,一旦b我正在与比较元件比的a元件更大的变更向量上> =不==)

这应该是很容易我想,这是一个自称功能的函数。 但我无法将头围住它。

我希望有人能够理解我想要做什么,但目前我无法更好地解释它。从理论上讲,我认为这对于向量的升序应该更快,因为您只需进行N次比较(N代表更大的向量的大小),而不是N*M

+0

排序,归并排序 – user3528438

+1

我认为它会是有意义的解决这一算法,而不是试图通过优化循环。例如,对数组进行排序可能会导致相当多的优化。蛮力比较似乎是解决这个问题最不优雅的方式。通常这些阵列有多大? – tadman

+0

矢量的大小高达100万左右 –

回答

3

这是合并两个排序向量的经典问题的变化。

如果向量进行排序,你需要做的全部是矢量b执行增量线性搜索矢量a的时序元件。 b中的每个搜索都是从先前的搜索停止的地方开始的。这种方法将需要O(a.size() + b.size())比较。

int count = 0; 

int j = 0; 
for (int i = 0; i < a.size(); ++i) 
    for (; j < b.size() && b[j] <= a[i]; ++j) 
    if (b[j] == a[i]) 
     ++count; 

如果你仔细观察,你会发现这是完全一样的算法,如@ Anedar的答案,从一个“不同的制高点”刚表示。

然而,如果这两个向量有显著不同长度的(比如说,ab短得多),那么它可能是有意义采取的a时序元件和b二进制搜索。同样,b中的每个搜索都可以从之前找到的b元素中“向右”运行。这种方法将需要O(a.size() * log b.size())比较。

如果a.size() ~ b.size()O(a.size() + b.size())优于O(a.size() * log b.size())。但是如果a.size() << b.size(),那么它是相反的。

+0

感谢您的深入解答(是的,我认为它与@ Anedar一样)。 问题是,关于大小之间的关系没有定义。在一次迭代中它可以是1:1,在下一次迭代中可以是1:1000000。所以我必须找到一个中间点。或者使用阈值来选择二进制搜索和线性搜索... –

+0

@ Fl.pf .:理论上,您可以像这里描述的那样“融合”这两种方法:http://stackoverflow.com/a/12993740/ 187690。但在现实生活中,一个简单的门槛可能确实足够完美。 – AnT

3

既然你说,元素的顺序存储,你可以做这样的事情:

int i=0; 
int j=0; 

while(i< a.size() && j<b.size()){ 
    if(a[i]==b[j]){ 
    ++counter; 
    ++i; 
    ++j; 
    }else if(a[i]<b[j]){ 
    ++i; 
    }else{ 
    ++j; 
    } 
} 
+0

这么容易,但非常有效。非常感谢你,这是诀窍! (它仍然很慢,但现在工作;)) –

+0

是的,但最坏的情况下的复杂性仍然是N * M。假设A包含1000000个值并且B只有一个,但在某处结束。所以你必须逐个检查A的所有值,直到达到最后一个值。效率不高。 –

+0

@BajMile sry,但它的唯一O(N + M),正如AnT在他的(更优雅但相似的)解决方案中所述。你可以这样看:在每次迭代中,“i”或“j”都增加1,所以在最糟糕的情况下,最终会出现“i = N”和“j = M”这会导致两个蜂群同时增加),这需要与'2 *(N + M)'比较完全'N + M'增加。 – Anedar

0

如果不需要使用该向量,则可以使用std :: multiset作为两个集合中值的容器。

这个std :: multiset容器允许插入重复的值,并在相同的时间值被排序。你可以用std :: multiset :: count获取元素的数量。

O(logN)复杂度将执行一次检查,以检查B中是否包含所有来自B的值,并且最坏情况下的复杂计数是M(logN)。 std :: map可以达到同样的效果,但是设置的内存比map更少,使用起来也更简单。

如果值是在集合B中不止一次只有一个检查可以在集合A进行

+0

但是OP有*两个独立的*组数据。这是给出的。你如何在'O(log N)'中用'multisets'来解决这个问题?什么multisets具体?一个multiset还是两个multisets?如果你只是使用两个miltisets而不是两个向量,那么不会,你不能在'O(log N)'上解决。 – AnT

+0

O(log N)是A中的一项检查。要检查B中的所有值,您需要设置MO(log N)。但是如果B也被设置,M被减少为唯一值的数量。 –

+0

但是排序向量中的一个检查也是'O(log N)',这意味着在排序的向量中检查所有内容都是'O(M * log N)'。但是可以在'O(M + N)'中检查两个排序序列,如其他答案所示,当'M'和'N'接近时,它比'O(M * log N)'更好。这同样适用于集合和排序向量。事实上,在这种情况下,集合和排序向量之间绝对没有区别。这就是为什么我不清楚你想要做什么的具体问题。 – AnT