微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从 std::vector 中删除重复元素但从前面开始?

如何解决从 std::vector 中删除重复元素但从前面开始?

如何从向量中删除重复元素但从前面开始?

所以

2 3 4 5 2 5 会变成 3 4 2 5

1 5 3 1 会变成 5 3 1

我希望该解决方案易于阅读,如果它也具有良好的性能就好了。

解决方法

如果容器支持双向迭代器,那么您尝试从容器的哪一侧删除重复元素并不重要,因为您可以使用反向迭代器。

这是一个演示程序。

#include <iostream> 
#include <vector> 
#include <iterator> 
#include <algorithm> 
  
template <typename ForwardIterator> 
ForwardIterator remove_duplicates( ForwardIterator first,ForwardIterator last ) 
{ 
    for ( ; first != last; ++first ) 
    { 
        last = std::remove( std::next( first ),last,*first ); 
    } 
      
    return last; 
} 
  
int main() 
{ 
    std::vector<int> v = { 1,2,3,4,5,1 }; 
      
    for ( const auto &item : v ) std::cout << item << ' '; 
    std::cout << '\n'; 
  
    v.erase( remove_duplicates( std::begin( v ),std::end( v ) ),std::end( v ) ); 
      
    for ( const auto &item : v ) std::cout << item << ' '; 
    std::cout << '\n'; 
  
    std::cout << '\n'; 
      
    v.assign( { 1,1 } ); 
  
    for ( const auto &item : v ) std::cout << item << ' '; 
    std::cout << '\n'; 
      
    v.erase( std::begin( v ),remove_duplicates( std::rbegin( v ),std::rend( v ) ).base() ); 
     
    for ( const auto &item : v ) std::cout << item << ' '; 
    std::cout << '\n'; 
} 

程序输出为

1 2 3 4 5 4 3 2 1 
1 2 3 4 5 

1 2 3 4 5 4 3 2 1 
5 4 3 2 1 
,

渐近有效的算法(N log N):

  • 创建一系列迭代器,每个迭代器都指向原始容器
  • 使用 稳定 排序对迭代器进行排序。使用通过迭代器间接的比较函数。
  • 使用反向迭代器和类似的自定义比较函数删除连续的重复项 (std::unique)。
  • std::remove_if 从带有谓词函数的向量中删除其迭代器不在辅助容器中的元素。

它比 O(N*N) 解决方案复杂一点。这是一个示例实现。我不能保证它是正确的:

template<class It,class Sentinel>
auto remove_duplicates(It first,Sentinel last)
{
    std::vector<It> iterators;

    auto iterator_generator = [it = first]() mutable {
        return it++;
    };
    std::generate_n(
        std::back_inserter(iterators),last - first,iterator_generator);

    auto iterator_compare = [](const auto& l,const auto& r) {
        return *l < *r;
    };
    
    std::stable_sort(
        iterators.begin(),iterators.end(),iterator_compare);

    auto iterator_eq = [](const auto& l,const auto& r) {
        return *l == *r;
    };
    auto last_unique = std::unique(
        iterators.begin(),iterator_eq);
    iterators.erase(last_unique,iterators.end());

    auto keep_generator = [it = first]() mutable {
        return it++;
    };
    std::vector<bool> remove(last - first,true);
    for(auto it : iterators) {
        auto index = it - first;
        remove[index] = false;
    }
    
    auto remove_predicate = [index = 0,remove = std::move(remove)](const auto& el) mutable {
        return remove[index++];
    };
    return std::remove_if(first,std::move(remove_predicate));
}

// usage with reverse iterators
v.erase(
    v.rend().base(),remove_duplicates(v.rbegin(),v.rend()).base());

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。