排序一对向量

the*_*ine 8 c++ sorting vector

我知道如何对一对矢量进行排序,但是你如何对一对矢量进行排序?我可以考虑在一对向量上编写一个自定义的"虚拟"迭代器并对其进行排序,但这看起来非常复杂.有没有更简单的方法?C++ 03中有一个吗?我想用std::sort.

当处理在硬件中生成的一些数据时出现这个问题,其中一对数组比对数组更有意义(从那时起会出现各种步幅和对齐问题).我意识到,否则保持一对向量而不是对的向量将是一个设计缺陷(数组问题的结构).我正在寻找一个快速的解决方案,将数据复制到成对的向量然后返回(我将它返回到HW以进行更多处理)不是一个选项.

例:

keys   = {5, 2, 3, 1, 4}
values = {a, b, d, e, c}
Run Code Online (Sandbox Code Playgroud)

排序后(通过第一个向量):

keys   = {1, 2, 3, 4, 5}
values = {e, b, d, c, a}
Run Code Online (Sandbox Code Playgroud)

我将"一对矢量"称为一对keysvalues(存储为例如std::pair<std::vector<size_t>, std::vector<double> >).矢量具有相同的长度.

seh*_*ehe 5

让我们做一个排序/置换迭代器,这样我们就可以说:

int  keys[] = {   5,   2,   3,   1,   4 };
char vals[] = { 'a', 'b', 'd', 'e', 'c' };

std::sort(make_dual_iter(begin(keys), begin(vals)), 
          make_dual_iter(end(keys), end(vals)));

// output
std::copy(begin(keys), end(keys), std::ostream_iterator<int> (std::cout << "\nKeys:\t",   "\t"));
std::copy(begin(vals), end(vals), std::ostream_iterator<char>(std::cout << "\nValues:\t", "\t"));
Run Code Online (Sandbox Code Playgroud)

看到Live On Coliru,打印

Keys:   1   2   3   4   5   
Values: e   b   d   c   a   
Run Code Online (Sandbox Code Playgroud)

根据这里的想法,我实现了这个:

namespace detail {
    template <class KI, class VI> struct helper { 
        using value_type = boost::tuple<typename std::iterator_traits<KI>::value_type, typename std::iterator_traits<VI>::value_type>;
        using ref_type   = boost::tuple<typename std::iterator_traits<KI>::reference,  typename std::iterator_traits<VI>::reference>; 

        using difference_type = typename std::iterator_traits<KI>::difference_type;
    };
}

template <typename KI, typename VI, typename H = typename detail::helper<KI, VI> > 
class dual_iter : public boost::iterator_facade<dual_iter<KI, VI>, // CRTP
    typename H::value_type, std::random_access_iterator_tag, typename H::ref_type, typename H::difference_type> 
{ 
public: 
    dual_iter() = default;
    dual_iter(KI ki, VI vi) : _ki(ki), _vi(vi) { } 

    KI _ki; 
    VI _vi; 

private: 
    friend class boost::iterator_core_access; 

    void increment() { ++_ki; ++_vi; } 
    void decrement() { --_ki; --_vi; } 

    bool equal(dual_iter const& other) const { return (_ki == other._ki); } 

    typename detail::helper<KI, VI>::ref_type dereference() const { 
        return (typename detail::helper<KI, VI>::ref_type(*_ki, *_vi)); 
    } 

    void advance(typename H::difference_type n) { _ki += n; _vi += n; } 
    typename H::difference_type distance_to(dual_iter const& other) const { return ( other._ki - _ki); } 
}; 
Run Code Online (Sandbox Code Playgroud)

现在工厂的功能很简单:

template <class KI, class VI> 
    dual_iter<KI, VI> make_dual_iter(KI ki, VI vi) { return {ki, vi}; }
Run Code Online (Sandbox Code Playgroud)

注意 我通过使用boost/tuples/tuple_comparison.hpp排序我有点懒.当多个键值共享相同的值时,这可能会导致稳定排序的问题.但是,在这种情况下,很难定义什么是"稳定"排序,所以我认为现在不重要.

完整列表

Live On Coliru

#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/tuple/tuple_comparison.hpp>

namespace boost { namespace tuples {

    // MSVC might not require this
    template <typename T, typename U>
    inline void swap(boost::tuple<T&, U&> a, boost::tuple<T&, U&> b) noexcept {
        using std::swap;
        swap(boost::get<0>(a), boost::get<0>(b));
        swap(boost::get<1>(a), boost::get<1>(b));
    }

} }

namespace detail {
    template <class KI, class VI> struct helper { 
        using value_type = boost::tuple<typename std::iterator_traits<KI>::value_type, typename std::iterator_traits<VI>::value_type>;
        using ref_type   = boost::tuple<typename std::iterator_traits<KI>::reference,  typename std::iterator_traits<VI>::reference>; 

        using difference_type = typename std::iterator_traits<KI>::difference_type;
    };
}

template <typename KI, typename VI, typename H = typename detail::helper<KI, VI> > 
class dual_iter : public boost::iterator_facade<dual_iter<KI, VI>, // CRTP
    typename H::value_type, std::random_access_iterator_tag, typename H::ref_type, typename H::difference_type> 
{ 
public: 
    dual_iter() = default;
    dual_iter(KI ki, VI vi) : _ki(ki), _vi(vi) { } 

    KI _ki; 
    VI _vi; 

private: 
    friend class boost::iterator_core_access; 

    void increment() { ++_ki; ++_vi; } 
    void decrement() { --_ki; --_vi; } 

    bool equal(dual_iter const& other) const { return (_ki == other._ki); } 

    typename detail::helper<KI, VI>::ref_type dereference() const { 
        return (typename detail::helper<KI, VI>::ref_type(*_ki, *_vi)); 
    } 

    void advance(typename H::difference_type n) { _ki += n; _vi += n; } 
    typename H::difference_type distance_to(dual_iter const& other) const { return ( other._ki - _ki); } 
}; 

template <class KI, class VI> 
    dual_iter<KI, VI> make_dual_iter(KI ki, VI vi) { return {ki, vi}; }

#include <iostream>
using std::begin;
using std::end;

int main()
{
    int  keys[] = {   5,   2,   3,   1,   4 };
    char vals[] = { 'a', 'b', 'd', 'e', 'c' };

    std::sort(make_dual_iter(begin(keys), begin(vals)), 
              make_dual_iter(end(keys), end(vals)));

    std::copy(begin(keys), end(keys), std::ostream_iterator<int> (std::cout << "\nKeys:\t",   "\t"));
    std::copy(begin(vals), end(vals), std::ostream_iterator<char>(std::cout << "\nValues:\t", "\t"));
}
Run Code Online (Sandbox Code Playgroud)

  • 使用 Boost 相当简洁。让我看看我是否明白,“boost::iterator_facade”为您实现了所有迭代器函数,仅基于“increment”、“decrement”、“equal”、“dereference”、“advance”和“distance_to” ?如果是这样,从我的无升压双迭代器的长度来看,这非常有用。比较不是问题,我可以轻松地为“std::sort”编写自己的比较谓词。 (2认同)