簡體   English   中英

兩個向量的集合交集的有效或快速大小

[英]Efficient, or fast, size of the set intersection of two vectors

我發現自己需要返回兩個向量的交集大小:

std::vector<int> A_, B_

我不需要相交的值,只需要集合的大小。 這個功能需要被調用很多次。 這是對(數學)圖形/網絡進行更大模擬的一部分。

我的工作條件是:

  • 容器是載體。 改變它們是純粹的痛苦,但如果獲得保證肯定會這樣做。
  • A_和B_的大小具有~100的上限。 但往往要小得多。
  • A_和B_的元素表示取自{1,2,...,M}的樣本,其中M> 10,000。
  • 通常,A_和B_具有相似但不相等的大小。
  • 兩個向量都是無序的。
  • 作為“更大模擬”的一部分,A_和B_的內容發生變化。
  • 每個向量僅包含唯一元素,即不重復。

我的第一次嘗試,使用一個天真的循環,在下面。 但我認為這可能還不夠。 我假設...由於重復的排序和分配,std :: set_intersection將過於繁重。

   int vec_intersect(const std::vector<int>& A_, const std::vector<int>& B_) {

      int c_count=0;

  for(std::vector<int>::const_iterator it = A_.begin(); it != A_.end(); ++it){
     for(std::vector<int>::const_iterator itb = B_.begin(); itb != B_.end(); ++itb){

      if(*it==*itb) ++c_count;
     }
  }

  return c_count;
}

鑒於我的上述條件,我還能如何實現這一點以獲得速度,相對容易? 我應該考慮哈希表還是使用排序和STL,或者不同的容器?

您的算法的元素數量為O(n 2 )(假設兩個向量的大小約等於n )。 這是一個O(n)算法:

  • 創建一個std::unordered_set<int>
  • 將矢量A所有項目放入集合中
  • 瀏覽向量B所有項目,檢查它們是否存在於unordered_set ,並遞增每個項目的計數。
  • 返回最終計數。

這是C ++ 11中的一個實現,使用lambda簡潔:

vector<int> a {2, 3, 5, 7, 11, 13};
vector<int> b {1, 3, 5, 7, 9, 11};
unordered_set<int> s(a.begin(), a.end());
int res = count_if(b.begin(), b.end(), [&](int k) {return s.find(k) != s.end();});
// Lambda above captures the set by reference. count_if passes each element of b
// to the lambda. The lambda returns true if there is a match, and false otherwise.

(這打印4 ; 演示

您的算法是O(n * m),其中n和m是向量中的元素數。

如果您沒有輸入數據不受信任的問題,您可能會獲得最佳結果:

  • A所有元素放入unordered_set
  • 對於B每個元素,如果它在集合中,則遞增計數器。

例如:

int vec_intersect(const std::vector<int>& A_, const std::vector<int>& B_)
{
    std::unordered_set<int> aSet(A_.cbegin(), A_.cend());
    return std::count_if(B_.cbegin(), B_.cend(), [&](int element) {
        return aSet.find(element) != aSet.end();
        });
}

這將概率地給出O(m + n)個結果。 (哈希表幾乎總是O(1),但如果攻擊者可以強制表中的許多沖突,他們可能會強制O(n)行為,導致拒絕服務)

如果您需要確定性結果,並且向量的順序無關緊要,則排序一個向量將起作用,即只有O(m lg m + m + n)。 那是:

  • 排序第一個向量
  • 對於第二個向量中的每個元素,使用二進制搜索來確定元素是否在第一個向量中,如果是,則遞增計數器。

例如:

int vec_intersect(std::vector<int>& A_, const std::vector<int>& B_)
{
    std::sort(A_.begin(), A_.end());
    return std::count_if(B_.cbegin(), B_.cend(), [&](int element) {
        return std::binary_search(A_.cbegin(), A_.cend(), element);
        });
}

只是為了咯咯笑,這是你的算法的<algorithm>化版本:

int vec_intersect(const std::vector<int>& A_, const std::vector<int>& B_)
{
    return std::count_if(B_.cbegin(), B_.cend(), [&](int element) {
        return std::find(A_.cbegin(), A_.cend(), element) != A_.cend();
        });
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM