【问题标题】:Removing duplicate elements in using the function "remove"使用“删除”功能删除重复元素
【发布时间】:2020-06-07 15:23:51
【问题描述】:

我尝试使用算法库中的函数remove,通过函数vectorremove从向量中删除重复元素,但它不起作用:

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;

void vectorremove(vector<string> v)
{
    for (vector<string>::iterator it = v.begin(); it != v.end(); ++it)
    {
        vector<string>::iterator end = remove(it + 1, v.end(), *it);
        v.erase(end, v.end());
    }
}

int main()
{
    vector<string> vect;
    string x;

    while (cin >> x)
    {
        vect.push_back(x);
    }

    vectorremove(vect);

    for (vector<string>::iterator it = vect.begin(); it != vect.end(); ++it)
    {
        cout << *it << endl;
    }
    return 0;
}

我写了这段代码来测试函数vectorremove是否有效,不幸的是vectorremove似乎对向量没有影响。我在vectorremove的定义中使用remove有什么错误吗?

【问题讨论】:

  • iterase 操作无效,而不是执行++it 你应该使用erase 的返回值
  • 同样你将向量按值传递给vectorremove函数,所以main中的vect保持不变
  • @M.M 能否请您详细说明如何使用erase 的返回值而不是++it
  • 有什么东西阻止你打开你的C++书到那一章告诉你如何使用erase(),自己阅读使用erase()的返回值的例子?这是每本 C++ 书籍都应该解释的基本内容,stackoverflow.com 不能替代 C++ 书籍。
  • 查找“擦除删除成语”。或阅读vector::erase的文档

标签: c++ algorithm vector


【解决方案1】:

您的代码中的第一个问题是您通过值传递向量,而不是通过引用vectorremove。您需要将其更改为

void vectorremove(vector<string>& v);

然后在您的vectorremove 函数中,您还有另一个问题。 vector::erase 可以使所有迭代器失效,所以你应该只在循环中使用remove,并在循环之后执行erase

void vectorremove(vector<string>& v)
{
    vector<string>::iterator end{ v.end() };
    for (vector<string>::iterator it = v.begin(); it != end; ++it)
    {
        end = remove(it + 1, end, *it);
    }
    v.erase(end, v.end());
}

【讨论】:

    【解决方案2】:

    首先,您通过值传递std::vector,而不是通过引用。因此,您在vectorremove 函数中所做的任何更改都不会在main 中可见。 此外,std::vector::erase 可能会使迭代器无效,因此您不能在循环中使用它。

    您的代码可能如下所示:

    void vectorremove(std::vector<std::string>& v) {
        auto end{ v.end() };
        for (auto it = v.begin(); it != end; ++it)
        {
            end = std::remove(it + 1, end, *it);
        }
        v.erase(end, v.end());
    }
    

    注意 auto 的用法,而不是 std::vector&lt;std::string&gt;::iterator

    但是,STL 提供了方便的函数来实现您想要的。其中之一是std::unique

    从每个连续的组中删除除第一个元素之外的所有元素 [first, last) 范围内的等效元素并返回一个 范围的新逻辑结束的结束迭代器。

    为了从std::vector 中删除重复项,您可以执行以下操作:

    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    int main()  {
        std::vector<int> v{ 1, 2, 3, 1, 2, 3, 3, 4, 5, 4, 5, 6, 7 };
        std::sort(v.begin(), v.end()); // 1 1 2 2 3 3 3 4 4 5 5 6 7 
        auto last = std::unique(v.begin(), v.end());
        v.erase(last, v.end());
        for (auto const i : v) {
            std::cout << i << " ";
        }
        std::cout << std::endl;
    
        return 0;
    }
    

    请记住,std::unique 按预期工作仅在排序后 std::vectors。

    【讨论】:

      【解决方案3】:

      你只修改vector的副本,你必须通过引用来修改实际 vector,为什么不使用 auto 而不是 std::vector::iterator。你必须 知道擦除使所有指向被擦除元素的迭代器无效,并且 除了被擦除的元素之外,通过使用擦除的返回值来保持迭代器的有效性,还在循环内使用 std::getline 来存储来自 std::cin 的值以包含新行。

      或者您可以使用 std::unique 删除重复值并在对元素进行排序后按预期工作。并且 std::unique 为范围的新逻辑结束返回一个结束迭代器:-

      #include <vector>
      #include <algorithm>
      #include <string>
      
      std::vector<std::string> removeDuplicate(std::vector<std::string> & v){
      
      std::vector<std::string> vec;
      
      std::sort(std::begin(v), std::end(v));
      auto pos = std::unique(std::begin(v), std::end(v));
      
      vec.assign(std::begin(v), pos);
      return vec;
      }
      
      
      int main(){
      
      std::vector<std::string> vect{"John", "John", "Paul", "John", "Lucy", "Bob", "Bob"};
      
      auto pureVector = removeDuplicate(vect);
      
      for(auto const & v : pureVector){
          std::cout << v << '\n';
      }
      
      }
      

      【讨论】:

        猜你喜欢
        • 2019-10-02
        • 2018-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-02
        • 2011-02-18
        • 1970-01-01
        相关资源
        最近更新 更多