【问题标题】:How to remove a pair of repeated occurrences in a list in c++? (keep elements that appear only once)如何删除 C++ 列表中重复出现的一对? (保留只出现一次的元素)
【发布时间】:2013-05-05 09:35:28
【问题描述】:

我尝试过使用unique,但unique 只删除了重复项。

我的程序应该做的是例如列表包含1,2,2,2,3,4,4。我想只删除重复的数字对,输出应该是1,2,3(删除了一对2和4)。

【问题讨论】:

  • 如果列表包含1,2,3,2,4,2,4怎么办?输出应该是1,2,3,2,4,2,41,2,3?
  • 应该是1,2,3。列表先排序。

标签: c++ algorithm list stl


【解决方案1】:

遍历数据并删除对(Live code):

list<int> data{1, 2, 2, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 6};

for (auto i = data.begin(); i != data.end();)
{
    auto n = std::next(i);

    if (n == data.end())
        break;

    if (*i == *n)
    {
        i = data.erase(i);
        i = data.erase(i);
    }
    else
        i++;
}

输出

1 2 3 4 5 6 

还有1 2 3 代表1 2 2 2 3 4 4

 

以上代码从 C++11 开始工作,如果你没有,试试这个:

for (list<int>::iterator i = data.begin(); i != data.end();)
{
    list<int>::iterator n = i; 
    n++;

    if (n == data.end())
        break;

    if (*i == *n)
    {
        i = data.erase(i);
        i = data.erase(i);
    }
    else
    i++;
}

【讨论】:

  • 我收到这个错误,说‘next’不是‘std’的成员。这有什么线索吗?
【解决方案2】:

我建议使用sortunique 函数来执行此操作。

std::sort (my_vector.begin(), my_vector.end() );
std::vector<int>::iterator it;
it = std::unique (my_vector.begin(), my_vector.end() );
my_vector.resize( std::distance(my_vector.begin(),it) );

参考:http://www.cplusplus.com/reference/algorithm/unique/ - 这里有一个示例,您可以使用predicate comparison 自定义unique 的行为。

编辑——如果您有兴趣删除连续元素,您可能还想查看std::adjacent_find

编辑——如果你只关心删除连续的元素,首先对列表进行排序,然后对其进行迭代。如果两个元素是连续的,请使用std::remove_if 或类似的方式删除它们。

【讨论】:

  • std::unique 可以使用predicate 函数进行修改,以实现您的自定义需求:) 我只是举了一个例子。
  • 我已经尝试过相邻查找,如果列表包含一个又一个相同的数字,例如 1,2,2,2,3..它会删除所有 2。我的要求是只删除一个一对 2.
【解决方案3】:

您可以轻松地循环浏览列表。获取第一个项目并搜索其他项目以进行完全匹配,如果找到,则将两者都删除。当循环结束时,您应该有一个没有任何对的列表。

【讨论】:

    【解决方案4】:

    如果您能想出一个不在列表中的哨兵值,这里有一个更通用的方法来处理这个问题。附带的好处是,这可能在向量上效果更好,因为 vector::erase 非常慢。

    #include <cassert>
    #include <vector>
    #include <iterator>
    #include <iostream>
    #include <algorithm>
    
    template <class ITR>
    void replace_pairs_with_sentinel(ITR begin, ITR end,
        const typename std::iterator_traits<ITR>::value_type& sentinel)
    {
        // handle empty sequence
        if ( begin == end ) return;
    
        // ensure no sentinel values exist
        assert ( std::find(begin, end, sentinel) == end );
    
        ITR prev = begin++;
        while ( begin != end ) {
            if ( *begin == *prev ) {
                *prev = *begin = sentinel;
            }
            prev = begin++;
        }
    }
    
    int main (int argc, char* argv[])
    {
        int data[] = {1, 2, 2, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 6};
        std::vector<int> v( data, data + sizeof(data) / sizeof(int) );
    
        replace_pairs_with_sentinel( v.begin(), v.end(), -INT_MAX );
        std::vector<int>::iterator end_itr = std::remove( v.begin(), v.end(), -INT_MAX );
        v.resize( end_itr - v.begin() );
        std::copy( v.begin(), v.end(), std::ostream_iterator<int>( std::cout, " " ) );
        return 0;
    }
    

    【讨论】:

    • 它适用于 std::list。这种方法需要对容器进行排序,但你说这个假设是有效的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-10
    • 2014-12-16
    • 1970-01-01
    • 1970-01-01
    • 2016-10-11
    相关资源
    最近更新 更多