如何比较和删除3个向量之间没有相同值的元素?

时间:2009-11-11 13:24:17

标签: c++

我需要删除3个向量或更多向量之间没有相同值的所有元素。 例如,

vector<int> Vector1, Vector2, Vector3;
for(int i = 2; i < 7; i++) Vector1.push_back(i); // Vector1 = {2, 3, 4, (5), (6)}
for(int i = 3; i < 8; i++) Vector2.push_back(i); // Vector2 = {3, 4, (5), (6), 7}
for(int i = 5; i < 10; i++) Vector3.push_back(i); // Vector3 = {(5), (6), 7, 8, 9}

我们知道所有向量都有2个具有相同值的元素:5和6.现在我如何获取这些值并将它们存储到新的向量中?

任何形式的帮助将不胜感激:)

7 个答案:

答案 0 :(得分:5)

标准算法库中有set_intersection(向量必须排序):

// This code does it for two vectors only

vector<int> a, b, r;

for(int i = 0; i < 10; i++)
{
    a.push_back(i);
    b.push_back(i+5);
}

set_intersection(
    a.begin(), a.end(),
    b.begin(), b.end(),
    back_inserter(r));

答案 1 :(得分:4)

如果所有向量都是有序的,那么每次检查最小数字时都要扫描它们,直到你将其中一个传递给另外两个。如果你找不到它,你就放弃它,每次检查你得到的最低数字。

示例:

T1 =第一个元素(v1) T2 = firest elemnt(v2) T3 =第一个元素(v3)

找出3之间的低位 如果没有平等 - 放下它并获得下一个val,然后再试一次。

如果所有向量的数字都上升(有序),您将找到所有匹配项。

答案 2 :(得分:2)

对我来说,最快的解决方案是使用所有向量中的元素构建集合。每次插入不唯一的元素时,都会增加其计数器。应删除具有相同数量的向量的元素。

然而,最简单的实现是制作地图(对于大多数情况,我认为它足够快):

// only pseudo code
map<int,int> elems;
for( vector<int>& v : vectors )
    for( int i : v ) {
        map<int,int>::iterator itr = elems.find(i);
        if( itr == elems.end() )
             elems[i] = 1;
        else itr->second++;
    }

for( pair<int,int>& p : elems )
    if( p.second == vectors.size() )
       erase_from_vectors( p.first );

如果你的向量非常庞大,你可以构建多值图,其值包含vector :: iterators。然后,您可以从矢量中删除这些元素,而无需查看它们。

答案 3 :(得分:0)

如果向量没有排序且无法对它们进行排序,则可以使用此(效率低)方法:

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

typedef std::vector<int> IntVec;
typedef std::vector<IntVec> TwoDIntVec;

IntVec
intvec_union(const TwoDIntVec& vec)
{
  IntVec result;
  size_t vec_size = vec.size();
  if (vec_size < 3) return result;
  const IntVec& vec1 = vec[0];
  size_t sz = vec1.size();
  for (size_t i=0; i<sz; ++i)
    {
      bool found = true;
      int val = vec1[i];
      for (size_t j=1; j<vec_size; ++j)
    {
      const IntVec& v = vec[j];
      if (std::find(v.begin(), v.end(), val) == v.end())
        {
          found = false;
          break;
        }
    }
      if (found) result.push_back(val);
    }
  return result;
}

// test
int
main()
{
  IntVec Vector1, Vector2, Vector3;
  for(int i = 2; i < 7; i++) Vector1.push_back(i); // Vector1 = {2, 3, 4, (5), (6)}
  for(int i = 3; i < 8; i++) Vector2.push_back(i); // Vector2 = {3, 4, (5), (6), 7}
  for(int i = 5; i < 10; i++) Vector3.push_back(i); // Vector3 = {(5), (6), 7, 8, 9}
  TwoDIntVec v;
  v.push_back(Vector1);
  v.push_back(Vector2);
  v.push_back(Vector3);
  IntVec result = intvec_union(v); // result = {5,6}
  return 0;
}

答案 4 :(得分:0)

这似乎有效,虽然它看起来很难看:

void intersection(std::vector<std::vector<int>*> valList, std::vector<int>& intersectionList)
{
    if(valList.size() < 2)
    {
        return;
    }

    std::vector<std::vector<int>*>::iterator iter = valList.begin();
    std::vector<std::vector<int>*>::iterator endIter = valList.end();

    for(; iter != endIter; ++iter)
    {
        std::vector<int>* pVec = *iter;
        std::sort(pVec->begin(), pVec->end());
    }

    iter = valList.begin();
    endIter = valList.end();

    std::vector<int>* pFirstVec = *iter;
    std::vector<int>* pSecondVec = *(iter + 1);

    iter = iter + 2;

    std::set_intersection(pFirstVec->begin(), pFirstVec->end(), pSecondVec->begin(), pSecondVec->end(), std::back_inserter(intersectionList));

    for(; iter != endIter; ++iter)
    {
        std::vector<int> temp;
        std::vector<int>* pVec = *iter;

        std::set_intersection(pVec->begin(), pVec->end(), intersectionList.begin(), intersectionList.end(), std::back_inserter(temp));

        intersectionList = temp;
        std::sort(intersectionList.begin(), intersectionList.end());
    }


}

int main()
{ 
    std::vector<int> Vector1, Vector2, Vector3, Vector4;
for(int i = 2; i < 7; i++) Vector1.push_back(i); // Vector1 = {2, 3, 4, (5), (6)}
for(int i = 3; i < 8; i++) Vector2.push_back(i); // Vector2 = {3, 4, (5), (6), 7}
for(int i = 5; i < 10; i++) Vector3.push_back(i); // Vector3 = {(5), (6), 7, 8, 9}
for(int i = 6; i < 12; i++) Vector4.push_back(i); // Vector3 = {(6),7,8,9,10,11}

std::vector<int> r;

std::vector<std::vector<int>*> v;
v.push_back(&Vector1);
v.push_back(&Vector2);
v.push_back(&Vector3);
v.push_back(&Vector4);

intersection(v,r);
    return 0;
}

答案 5 :(得分:0)

其他答案似乎假设向量已排序或没有重复值(我认为gba的答案在这种情况下失败)。 这个适用于所有情况,并仍然努力提高效率。它删除了每个向量中的所有元素。

template <class C>
struct is_in{
    const C & c_;
    bool b_;
    is_in(C c, bool b = true) : c_(c), b_(b) {}
    bool operator() (typename C::value_type v){
        return b_ == (c_.find(v) != c_.end());
    }
};

int main() {
    set<int> s(v.front().begin(), v.front().end());
    typedef is_in<set<int> > is_in_set;

    vector< vector<int> >::iterator i;
    for(i = v.begin()+1; i != v.end(); ++i) {
        //s is the intersection of every vectors before i
        set<int> new_s;
        //copy in new_s all elements of *i unless they are not in s
        remove_copy_if(i->begin(), i->end(), insert_iterator<set<int> >(new_s, new_s.begin()),
                is_in_set(s, false));
        swap(s, new_s);
    }

    for(i = v.begin(); i != v.end(); ++i) {
        //erase all elements of *i which are in s
        i->erase(remove_if(i->begin(), i->end(),
                is_in_set(s)), i->end());
    }
    vector<int> res_vec(s.begin(), s.end());
}

答案 6 :(得分:0)

这种方法依赖于对输入向量进行排序,但之后只会对要比较的当前和下一个向量进行线性遍历,将匹配元素保留在第一个向量中。它不需要对每个元素进行完整搜索。该算法具有合理的容器中性,只需要前向迭代器,因此可以使用向量,列表,单链表,原始数组等。

此算法的基本构建块是一个从排序范围中删除不在第二个排序范围内的元素的函数。我正在使用std::remove约定将不需要的元素交换到范围的末尾并返回指向不需要的元素的开头的迭代器。它是O(n + m)。

template<class Input1, class Input2>
Input1 inplace_intersection(Input1 first1, Input1 last1, Input2 first2, Input2 last2)
{
    using std::swap;

    Input1 nextslot(first1);

    for( ; first1 != last1; ++first1 )
    {
        // Skip elements from the second range that are
        // smaller than the current element.
        while( first2 != last2 && *first2 < *first1 )
            ++first2;

        // Do we have a match? If so keep
        if( first2 != last2 && !(*first1 < *first2) )
        {
            if( first1 != nextslot )
                swap( *first1, *nextslot );

            ++nextslot;
        }
    }

    return nextslot;
}

使用此构建块,您可以对已排序的向量进行操作。

std::vector<int> initial;

// fill...

std::vector<int>::iterator first = initial.begin(), last = initial.end();

last = inplace_intersection( first, last, scnd.begin(), scnd.end() );

last = inplace_intersection( first, last, thrd.begin(), thrd.end() );

// etc...

initial.erase( last, erase.end() );

如果您的输入向量没有排序,那么您可以在可能的情况下对它们进行排序,或以其他方式创建已排序的副本。