2017-08-03 59 views
2

我有兩個容器std::setstd::vector,我的任務是返回中存在的std::vector中的元素。什麼是最有效的方法來實現它? 簡單解決方案: 遍歷矢量元素,並在每個元素上調用set.find,然後vector.erase,如果未找到。在std :: set中查找std :: vector的元素

+3

矢量是排序還是未排序? – NathanOliver

+1

聽起來像你可能需要像['std :: set_union'](http://en.cppreference.com/w/cpp/algorithm/set_union)(但它需要對矢量進行排序)。 –

+0

對不一致。暫時(並且可能保持不變)向量未排序且很小。集合有更多的元素,但。 – rublow

回答

0

你可以使用更多的STL :)

#include <algorithm> 
#include <set> 
#include <vector> 
#include <iostream> 
#include <iterator> 

int main() { 
    std::vector<int> v {5, 4, 3, 2, 1}; 
    std::set<int> s {1, 3, 5}; 

    v.erase(std::remove_if(v.begin(), v.end(), 
          [&s](int a) { return s.find(a) == s.end(); }), 
      v.end()); 

    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " ")); 
} 
+0

因爲我想保持向量中的元素存在於集合中,所以解決方案需要一個小的校正'return s.find(a)== s.end()'; – rublow

+0

@rublow - 已更正 – tmp

2

如何尋找每一個元素?如果您的載體沒有排序,再有就是圍繞n log(n)

#include <algorithm> 

std::vector<int> result; 
for(auto&& el: myvector) { 
    auto it_found = myset.find(el); 
    if(it != myset.end()) 
     result.push_back(*it_found); 
} 

沒有辦法現在result擁有所有那些在這兩個元素。

PS:沒有編譯代碼,可能會有輕微的錯誤。

+0

不是100%肯定,但不是這個O(n^2)?你不需要迭代vector,然後使用set的'find'成員函數來獲得O(n log n)? – NathanOliver

+0

@NathanOliver其實我不確定。它可能是'n^2'。我有點不知所措,因爲'std :: set'是排序的。 –

+0

但是你沒有搜索這個集合。 'for(auto && el:myset)'遍歷這些集合,使之成爲'n',然後'std :: find(myvector.begin(),myvector.end(),el);'搜索另一個'那麼'O(n^2)'對嗎? – NathanOliver

0

您應該對矢量進行排序(如有必要,請保留原始索引,製作pair),然後使用binary search搜索矢量。這會更快。

或者您可以使用std::find方法,該方法可能會很慢。

+0

很確定你不想排序,如果它沒有排序。排序是O(n log n),那麼你有另一個O(n log n)進程。整個過程至少可以在一個O(n log n)過程中完成。 – NathanOliver

+0

對於一個單一的號碼,你需要'n'的複雜性。由於集合中可以有多個數字,所以這個線性搜索必須重複。 – Ultraviolet

0

最短路可能是用std::set_intersection。但是,你應該排序向量,使其工作:

int main() 
{ 
    std::set<int> s{1,2,3,4,5,6,7,8}; 
    std::vector<int> v{7,5,10,9}; 
    std::sort(v.begin(), v.end()); // should not bother you if vector is small 

    std::vector<int> intersection; 
    std::set_intersection(s.begin(), s.end(), v.begin(), v.end(), std::back_inserter(intersection)); 

    for(int n : intersection) 
     std::cout << n << ' '; 
} 

打印:5 7

+0

如果我錯了,糾正我,但它仍然是N logN – rublow

+1

如果'n'是向量的大小,'m'是該集合的大小,這是'O(n * lg(n)+ n +米)'。它可以在'O(n * lg(m))'中完成。 (並且設置迭代很慢。) – molbdnilo

0

根據集和載體的相對大小,可能的remove_if是正確的事情...

#include <set> 
#include <vector> 
#include <iostream> 
#include <algorithm> 

int main() 
{ 
    std::set<int> s{1,2,3,4,5,6,7,8}; 
    std::vector<int> v{7,5,10,9}; 

    v.erase(std::remove_if(v.begin(), v.end(), [&](int e){return s.count(e) == 0;}), v.end()); 


    for(int n : v) 
     std::cout << n << ' '; 
} 
0

如果你找最多CPU複雜方面這樣做的 - 有效方式,具有額外的內存和一個好的哈希函數,你能做到在O(N + M):

std::vector<int> v; 
std::set<int> s; 
std::unordered_set<int> us{s.cbegin(), s.cend(), s.size()}; 

v.erase(
    std::remove_if(v.begin(), v.end(), 
     [&us] (const int entry) { return us.find(entry) == us.cend(); }), 
    v.end()); 

說明:您遍歷您(O(m))準備unordered_set。然後你遍歷你的vector一次(O(n)),每步執行unordered_set::find(0(1))。它給你O(n + m)的複雜性。

另外,unordered_set的大小等於set的大小,並且良好的散列函數有助於減少std::unordered_set::find的複雜性中的不變部分。

請參閱live example

但是,請記住,較低的複雜度並不一定意味着在特定情況下執行速度更快(例如,由於額外分配)。

+0

謝謝您的解釋。然而(正如你所提到的),我想在不使用額外內存的情況下刪除元素。 – rublow

+0

在這種情況下,如果你不關心set的屬性或者使用[boost :: multi_index_container](http://www.boost.org/doc/libs/),你可以用'unordered_set'替換'set' 1_64_0/libs/multi_index/doc/tutorial/index.html),它使用'ordered_unique'索引類型來利用'set'類屬性和'hashed_unique'來過濾O(n)複雜度不需要的條目。 –

相關問題