【问题标题】:Step/Stride Iterator for use with std::minmax_element与 std::minmax_element 一起使用的步长迭代器
【发布时间】:2016-10-02 06:06:46
【问题描述】:

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

【问题讨论】:

    标签: c++ boost stl


    【解决方案1】:

    使用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,一个用于 max。


    给定一个随机访问迭代器,构建一个向前迈进的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 来说应该足够了。 (添加一点逻辑,decrement 和 advance 成员,并更改标签,也将使其成为随机访问迭代器。)

    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;
    }
    

    【讨论】:

    • 谢谢阿米。你能分享一下boost stride的代码示例吗?我无法访问 gcc 4.8.3 中似乎不存在的 range-v3。我也希望它可以与 C 风格的数组一起使用。
    • @RajatGupta 查看更新。不过,顺便说一句,开始熟悉范围是个好主意。
    猜你喜欢
    • 1970-01-01
    • 2022-10-07
    • 1970-01-01
    • 1970-01-01
    • 2013-05-19
    • 2018-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多