首页 文章

删除两个向量C中的相似元素

提问于
浏览
1

我试图搜索两个相同的元素的矢量(每个任何大小),然后删除这两个元素 .

我的实现如下:

for (int i = vec1.size() - 1; i >= 0; i--) {
     for (int j = 0; j < vec2.size(); j++) {
          if (vec1[i] == vec2[j]) {
             vec1.erase(vec1.begin() + i);
             vec2.erase(vec2.begin() + j);
          }
     }
}

然而,虽然这适用于大多数情况,但我遇到了一些它没有的地方 . 这是我通过这些向量迭代的方式,还是我只是这样做错了?

4 回答

  • 2

    尝试使用 std::set_difference 从另一个向量中减去一个向量,并在 std::merge 的帮助下合并这些减法 . 但是需要对向量进行排序以使用这些函数,因此首先使用 std::sort . 代码在这里:

    void TraceVector( std::vector<int> v, const std::string& title )
    {
        if ( !title.empty() )
        {
            std::cout << title << std::endl;
        }
    
        std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ","));
        std::cout << std::endl;
    }
    
    int main() {
    
        std::vector<int> Vec1 {7, 1, 2, 5, 5, 5, 8, 9};
        std::vector<int> Vec2 {3, 2, 5, 7, 10};
        std::vector<int> Difference1; // Contains subtraction Vec1 - Vec2
        std::vector<int> Difference2;// Contains subtraction Vec2 - Vec1
        std::vector<int> Merged; // RESULT Merged vector after subtractions
    
        //Need to be sorted
        std::sort(Vec1.begin(), Vec1.end());
        std::sort(Vec2.begin(), Vec2.end());
    
        TraceVector(Vec1, "Vec1 sorted is: ");
        TraceVector(Vec2, "Vec2 sorted is: ");
    
        //Make subtractions
        std::set_difference(Vec1.begin(), Vec1.end(), Vec2.begin(), Vec2.end(),
                            std::inserter(Difference1, Difference1.begin()));
        std::set_difference(Vec2.begin(), Vec2.end(), Vec1.begin(), Vec1.end(),
                            std::inserter(Difference2, Difference2.begin()));
    
    
        TraceVector(Difference1, "Difference is: ");
        TraceVector(Difference2, "Difference is: ");
    
        //Merge subtrctions
        std::merge(Difference1.begin(), Difference1.end(), Difference2.begin(), Difference2.end(), back_inserter(Merged));
        TraceVector(Merged, "Merged is: ");
    }
    

    输出是:

    Vec1 sorted is: 
    1,2,5,5,5,7,8,9,
    Vec2 sorted is: 
    2,3,5,7,10,
    Difference is: 
    1,5,5,8,9,
    Difference is: 
    3,10,
    Merged is: 
    1,3,5,5,8,9,10,
    Program ended with exit code: 0
    
  • 1

    如果你可以排序,你可以做这样的事情:

    #include <algorithm>
    #include <iostream>
    #include <vector>
    
    int main() {
    
      std::vector<int> ex {3, 1, 2, 3, 3, 4, 5}, as {2, 3, 6, 1, 1, 1}, tmp;
    
      std::sort(std::begin(ex), std::end(ex));
      std::sort(std::begin(as), std::end(as));
    
      as.erase(
        std::remove_if(
          std::begin(as),std::end(as),
          [&](int const& s){
            bool found = std::binary_search(std::begin(ex), std::end(ex), s);
            if (found) {
              tmp.push_back(s);
            }
            return found;}), std::end(as));
      for (auto const& i : tmp) {
        ex.erase(std::remove(std::begin(ex),std::end(ex), i), std::end(ex));
      }
    
    }
    
  • 1

    问题是,在从 vec1vec2 删除元素后循环遍历 vec2 时,您将继续访问 vec1[i] . 如果在删除 vec1 中的最后一个元素后执行此操作,则会导致未定义的行为,因为 vec1[i] 不再有效 . 在 if 中添加 break 语句来解决此问题 .

    for (int i = vec1.size() - 1; i >= 0; i--) {
         for (int j = 0; j < vec2.size(); j++) {
              if (vec1[i] == vec2[j]) {
                 vec1.erase(vec1.begin() + i);
                 vec2.erase(vec2.begin() + j);
                 break; // Look at next element in vec1
              }
         }
    }
    

    还有一种更有效的方法( O(n*log(n)+m*log(m)+n+m) 代替 O(n*m) 代表 n=vec1.size()m=vec2.size() ) . 它涉及对矢量进行排序 . 我会留给你弄清楚的 .

  • 0

    实际上你根本不需要向后迭代 . 在这种情况下,您的代码可以是:

    for (int i = 0; i < vec1.size(); i++) {
         for (int j = 0; j < vec2.size(); j++) {
              if (vec1[i] == vec2[j]) {
                 vec1.erase(vec1.begin() + i);
                 vec2.erase(vec2.begin() + j);
              }
         }
    }
    

    但等等......我们擦除一个元素后会发生什么?然后它之后的所有元素的索引都减少了1,所以我们将跳过下一个项目!要解决这个问题,我们可以添加这个小修改:

    vec1.erase(vec1.begin() + i--);
                 vec2.erase(vec2.begin() + j--);
                                           ^^^^
    

    即使我们通过擦除来改变大小,这也会起作用,因为我们正在检查 vec2 每个循环的大小!但是如果我们最终删除了 vec1 的最后一项呢?我们在 vec2 期间一直在迭代,这将是你的 vec1 = {2}, vec2 = {2, 2, 2} 例子中的一个问题 . 为了解决这个问题,我们可以突破内循环并重复检查 vec2 .

    把它们放在一起(并将你的下标操作符更改为 .at() 调用,这样我们就可以进行边界检查),你得到:

    for (int i = 0; i < vec1.size(); i++) {
         for (int j = 0; j < vec2.size(); j++) {
              if (vec1.at(i) == vec2.at(j)) {
                 vec1.erase(vec1.begin() + i--);
                 vec2.erase(vec2.begin() + j--);
                 break;
              }
         }
    }
    

    (见此处的行动:ideone

相关问题