用于std :: minmax_element的{Step / Stride Iterator

时间:2016-10-02 06:06:47

标签: c++ boost stl

我有一个浮点数组,表示浮点值的m * n(行和列)表。我的要求是为每行和每列找到最小/最大元素。对于行,我可以通过指定n个元素的范围使用std :: minmax_element来轻松完成。但是对于列我需要使用步长迭代器,因为放置的元素不是连续的,而是以n的步长间隔放置。是否可以使用boost / STL中的标准迭代器。另一种选择是编写我自己的版本。 什么是最好的课程?

1 个答案:

答案 0 :(得分:8)

执行此操作的两种方式(使用range-v3(或boost::range)和boost::iterator

使用range-v3,立即:

#include <iostream>
#include <range/v3/all.hpp>

using namespace ranges;

int main() {
    std::vector<std::size_t> src{1, 2, 3, 4, 5, 6, 7};
    const auto min_max = minmax(src | view::stride(3));
    std::cout << min_max.first << " " << min_max.second << std::endl;
}

boost::range中,使用boost::adaptors::strided

#include <boost/range/adaptor/strided.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/assign.hpp>
#include <boost/range/algorithm.hpp>
#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    using namespace boost::adaptors;
    using namespace boost::assign;

    std::vector<int> input;
    int arr[] = {1, 2, 3, 4, 5, 6, 7};

    auto str = std::make_pair(&arr[0], &arr[8]) | strided(3);
    std::cout << *boost::range::min_element(str) << " " << *boost::range::max_element(str) << std::endl;
}

请注意以下事项:

  1. 范围可以由一对迭代器定义,所以我在这里使用了它,虽然可以使用更简单的形式(它适合堆分配的C风格数组的用例)。

  2. 不幸的是,这个子库似乎没有min-max(或者至少我找不到它),所以有两个调用,一个用于min,一个用于最大

  3. 给定一个随机访问迭代器,构建一个跨步前进boost::iterator_facade并不是很困难:

    #include <iostream>
    #include <vector>
    #include <iterator>
    #include <cstddef>
    #include <algorithm>
    #include <boost/iterator/iterator_facade.hpp>
    
    template<typename It>
    class stride_iterator :
        public boost::iterator_facade<
            stride_iterator<It>,
            typename std::iterator_traits<It>::value_type,
            boost::forward_traversal_tag> {
    public:
        stride_iterator() = default;
        stride_iterator(It it, It end_it, std::size_t stride) : 
            m_it{it}, m_end_it{end_it}, m_stride{stride} 
        {}
    
    private:
        friend class boost::iterator_core_access;
    
        void increment() { 
            if(std::distance(m_it, m_end_it) < m_stride) {
                m_it = m_end_it;
                return;
            }
            std::advance(m_it, m_stride);
        }
    
        bool equal(const stride_iterator<It> &other) const {
            return m_it == other.m_it;
        }
    
        typename std::iterator_traits<It>::value_type &dereference() const { 
            return *m_it; }
    
        It m_it, m_end_it;
        std::size_t m_stride;
    };
    

    这对std::minmax_element来说应该足够了。 (添加一些逻辑,decrementadvance成员,以及更改标记,也会使其成为随机访问迭代器。)

    int main() {
        using vec_t = std::vector<int>;
        vec_t v{1, 2, 3, 4, 5, 6, 7};
        stride_iterator<vec_t::iterator> b{std::begin(v), std::end(v), 3}, e{std::end(v), std::end(v), 3};
        auto min_max = std::minmax_element(b, e);
        std::cout << *min_max.first << " " << *min_max.second << std::endl;
    }