【问题标题】:c++ max_element every n elementc ++ max_element每n个元素
【发布时间】:2018-04-13 20:51:32
【问题描述】:

有没有办法在容器中找到最大元素,比较每 N 个元素并返回索引。使用 STL、BOOST 或...其他库?

对于每个 N,我的意思是使用 std::max_element,但是将 for 的增加从 ++first 更改为 first += n;

// based on std::max_element

#ifndef NEWTON_ALGORITHM_SEARCH_MAX_INDEX_HPP
#define NEWTON_ALGORITHM_SEARCH_MAX_INDEX_HPP

#include <iterator>

#include <newton/functional.hpp>

namespace newton {

  // SAME THAT STD::MAX_ELEMENT
  template<class ForwardIt, class Compare>
  const ForwardIt max_index(ForwardIt first, ForwardIt last, Compare comp)
  {

    if ( newton::equal(first, last) ) // newton::equal is basically equivalent to std::equal_to
      return last;

    ForwardIt largest = first;
    while ( newton::not_equal(++first, last) )
      if (comp(*largest, *first))
        largest = first;

    return largest;

  }

  // possible names
  // max_index_some
  // max_index_every_n
  // max_index__n

  template<class ForwardIt, class Size, class Compare>
  const ForwardIt max_index_every_n(ForwardIt first, ForwardIt last, Size n, Compare comp)
  {

    if ( newton::equal(first, last) )
      return last;

    ForwardIt largest = first;
    Size blocks = std::distance(first, last) / n; // integer blocks

    if ( newton::greater_equal(blocks, 1) ) {

      // if there are exacly N elements, can't sum example
      // v.size() = 10, first start in 0, so "0 += 10" is "10", but last index is "9"
      // but if mod >= 1, then index is at least 10, so can sum

      if ( newton::greater_equal( std::distance(first, last) % n, 1) ) {
        for (size_t i = 1; newton::less_equal(i, blocks); ++i, first += n) {

          if (comp(*largest, *first))
            largest = first;
        }
      }
      else {

        for (size_t i = 1; newton::less(i, blocks); ++i, first += n) {

          if (comp(*largest, *first))
            largest = first;
        }

      }

    }

    return largest;

  }

  template<class ForwardIt>
  const ForwardIt max_index(ForwardIt first, ForwardIt last)
  {
    return max_index(first, last, newton::structure::less());
  }
} // newton

如果没有,您有什么解决方案来尝试将其包含在下一个 STL 版本中。 remember

【问题讨论】:

  • 也许开发一个带有自定义迭代器的容器?如果 boost 或其他库中没有这样的“步幅”迭代器,我会感到惊讶。

标签: c++ boost std


【解决方案1】:

使用range-v3,它将是:

auto r = v | ranges::view::stride(n);
auto it = ranges::max_element(r);

【讨论】:

  • 效率高吗? max_element(const ForwardRange&amp; rng) { BOOST_RANGE_CONCEPT_ASSERT(( ForwardRangeConcept&lt;const ForwardRange&gt; )); return std::max_element(boost::begin(rng), boost::end(rng)); } 我正在阅读 v2,这就是代码,V3 说这个if(begin != end) for(auto tmp = next(begin); tmp != end; ++tmp) if(invoke(pred, invoke(proj, *begin), invoke(proj, *tmp))) begin = tmp; return begin; 我不想每次都一个接一个地传递元素。我什么时候可以+= N
【解决方案2】:

仅使用 Boost(可以说是“Range V2”):

Live On Coliru

#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/algorithm_ext.hpp>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> v(100);
    boost::iota(v, 0);

    int n = 17;
    auto it = boost::max_element(v | boost::adaptors::strided(n));

    std::cout << "max: " << *it << "\n";
}

打印

max: 85

替代用法

您不必使用范围算法等等。您也可以根据需要选择:

Live On Coliru

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

int main() {
    std::vector<int> v { 1,2,3,4,5,6,7,8,9,10 };

    auto v_ = boost::adaptors::stride(v, 7);
    auto it = std::max_element(v_.begin(), v_.end());

    std::cout << "max: " << *it << "\n";
}

打印

max: 8

【讨论】:

  • 但是你执行的是普通的 std::max_element ,对吧?我的意思是,如果我有一个大小为 10⁶ 的向量,并且我想每隔 10⁵ 进行一次比较,那么当我只能比较 10 时,我会比较所有 10⁶。如果发生这种情况,那非常……非常……记住KISS。
  • 我相信我已经展示了两者。执行“正常算法”并不意味着它会访问所有元素!这就是算法和容器在 C++ 中分离的原因。换句话说,我并不傻,我回答了你的问题,就像另一个答案一样(如果你能负担得起像 Range v3 这样的前沿库)。此外,在您进行分析之前,不要假设什么更快。分支预测、自动矢量化和缓存预取会让您大吃一惊
  • @MoisesRojo 您甚至没有看到您正在阅读的答案。只是...自己尝试一下:coliru.stacked-crooked.com/a/6f79f773b909d1f2 甚至是coliru.stacked-crooked.com/a/24b5038734b318dccoliru.stacked-crooked.com/a/e32a5d4ecdfb494a。请注意,在第二个示例中看到 ++it 应该完全your confusion 的来源。当您看到输出时,您会有所启发。确实是亲吻。
  • KISS 不是个人的,我比你更 S。
  • private: void increment() { m_offset += m_stride; } 是的,现在我知道它是如何工作的了。
猜你喜欢
  • 2015-08-09
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 2013-06-12
  • 2012-11-08
  • 1970-01-01
  • 2011-07-08
  • 2011-03-28
相关资源
最近更新 更多