成对函数求值算法(C++,STL)
Algorithm for function evaluation by pairs (C++, STL)
我需要成对将自定义func
应用于 STL 容器 ->即:
// if c => {a,b,c,d,e,f,g}; // a,b,c,.. are just aliases for some object
my_algorithm(c.begin(),c.end(),[](auto a, auto b){ a + b }); // c++14
应该解析成这样:
temp1 = a + b;
temp2 = c + d;
temp3 = e + f;
temp4 = temp1 + temp2;
temp5 = temp3 + g;
result = temp4 + temp5;
(我确定这种算法有一个正确的名称,但我不知道这可能是什么(
我已经尝试过std::accumulate
,我不确定它的实现是否由标准定义,但就我而言,使用我的编译器,它似乎可以解决这个问题(我认为这称为成对求和,对吧?
temp1 = a + b;
temp2 = temp1 + c;
temp3 = temp2 + d;
// etc
这更不像我能得到的一样
auto temp = c[0];
std::for_each(c.begin()+1,c.end(),[&temp](auto a){temp + a); // c++14
我浏览了STL和Boost,但没有找到相关的东西。有没有提供这种算法的库?如果没有,有什么想法可以很好地实现STL兼容吗?
编辑补充一点,我对添加传统意义上的元素并不真正感兴趣 - 在这种情况下,顺序并不重要。我的函数将执行更复杂的加权求和,如果以这种方式执行,将给出不同的结果。不过,我的问题更笼统。
以下是我对 C++11 标准的 STL 兼容解决方案的尝试:
#include <cassert>
#include <cmath>
#include <cstddef>
#include <array>
#include <iostream>
#include <iterator>
namespace detail {
// Returns first power of two which is strictly less than n
unsigned int pot_half(std::ptrdiff_t n) {
assert(n > 1);
return 1 << (static_cast<unsigned int>(ceil(log2(n))) - 1);
}
} // end namespace detail
struct tree_fold_on_empty_range : std::exception {};
template <typename Iterator, typename F>
auto tree_fold(const Iterator & begin, const Iterator & end, F && func) -> decltype(func(*begin, *end)) {
std::ptrdiff_t diff = end - begin;
switch (diff) {
case 0: throw tree_fold_on_empty_range{}; // or, return {}; ?
case 1: return *begin;
case 2: return func(*begin, *(begin + 1));
default: {
Iterator mid{begin};
std::advance(mid, detail::pot_half(diff));
return func(tree_fold(begin, mid, func), tree_fold(mid, end, func));
}
}
}
int main() {
for (uint n = 2; n < 20; ++n) {
std::cout << n << " -> " << detail::pot_half(n) << std::endl;
}
std::cout << std::endl;
std::array<int, 8> test{1, 2, 3, 4, 5, 6, 7, 8};
std::cout << tree_fold(test.begin(), test.end(), [](int a, int b){ return a + b; }) << std::endl;
std::cout << tree_fold(test.begin(), test.end(), [](int a, int b){ return a - b; }) << std::endl;
}
也住在科里鲁,
它给出这个作为最终输出:
36
0
我相信这表明它是正确的:
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 = 36
((1 - 2) - (3 - 4)) - ((5 - 6) - (7 - 8)) =
((-1) - (-1)) - ((-1) - (-1)) =
0 - 0 = 0
请注意,在不是 2 的幂的范围内,"正确"行为有点模棱两可。在我的版本中,我所做的总是以小于 n
的 2 的第一次幂拆分长度范围n
。所以如果你给它一个2的幂,你总是得到一个完美平衡的二叉树。如果你给它 6,你会得到这样的东西:
/
/ /
/ /
然而,没有什么说总是除以二也是不正确的,所以你会得到这样的树结构
/
/ /
/ /
所以IMO你的问题有点不够明确。也许这对你来说并不重要,只要深度O(log n)
?
自 2015 年 11 月以来,我一直在所谓的 VectorFuncRange 容器中工作,该容器在 C++14 中以 STL 风格解析该容器。
我做了我自己的测试版,它可以很好地模仿 std::vector 容器,但使用 func_range(( 方法在 O(log n( 中返回一个范围内的函数计算,评估为树。我赞同即使在内部评估为树,它们也只是向量,并且具有 O(1( 随机访问、摊销 O(1( 和最坏情况 O(log n( 等push_back。一些 std::vector 方法还没有由我编程,如 emplace_back(( 和不同的结构,但用作向量的主要方法是。出于测试原因,我将 rang_func(( 与 range_func_dumb(( 进行比较,第二个版本按线性顺序评估函数。
VectorFuncRange.h 我当前的版本: http://pastebin.com/dnwznUqg以 5 种不同方式执行此操作的测试代码,具有整数、矩阵和其他类型以及许多函数:http://pastebin.com/YdRfN0CQ
我曾考虑过放入公共 Git,但我想我应该在此之前组织更多的代码,我不知道其他人是否有兴趣贡献。
你应该看看std的第二种形式::transform:http://www.cplusplus.com/reference/algorithm/transform/
在 C++ 11 附近的伪代码中,算法的 STL 实现可能如下所示:
c = {a,b,c,d,e,f,g} // container of elements of type 'my_obj'
tmp = {a,b,c,d,e,f,g} // copy of 'c' to not impact 'c' while executing algorithm
while (tmp.size() > 1)
{
// partition 'tmp' into even index elements 'c1' and odd index elements 'c2'
// first iteration would look like this :
// c1 = {a,c,e,g}
// c2 = {b,d,f,identity} where 'idendity' is a new element (when 'tmp' size is odd) to match 'g' without impacting final result... identity = 0 for integers addition :)
// overwrite first elements of 'tmp' with intermediate results
std::transform(c1.cbegin(), c1.cend(), c2.cbegin(), tmp.begin(), std::plus<my_obj>()); // replace std::plus with any other binary operation including any proper lambda
// cut 'tmp' ununsed upper half
tmp.resize(size_t(0.5 * (tmp.size() + 1)));
}
my_obj result = tmp[0];
显然,在开始时复制"c"并在每次迭代时将"tmp"分成两半是有代价的。您决定如何从这里进行优化:)
考虑到一些建议的解决方案(特别是Chris Beck的解决方案(,我想出了这个算法,我现在正在尝试进一步优化。我已将其移至其他线程,因为我认为代码打开了许多值得自行讨论的问题。
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 在C应用程序中运行C++(带有STL)函数
- 使用2个键的cpp-stl::优先级队列排序不正确
- 在STL容器中使用模板类
- 用C++中的CPerson(类)类型的对象初始化STL矢量
- 将stl字符串缩小到小于15个字符的容量
- 在为LINUX创建共享库时,如何避免STL的私有/弱副本
- 检查函数返回类型是否与STL容器类型值相同
- STL算法函数在多个一维容器上的使用
- 在STL - C++中按成绩对学生列表进行排序?
- 为什么 STL 容器适配器堆栈中的 top 返回常量引用?
- λ可以适应STL吗?
- 为什么使用 NDK 不能存在不同的 stl 实现?
- 如果我真的真的想从 STL 容器继承,并且我继承构造函数并删除新运算符,会发生什么?
- 使用 char 分隔符解析C++中的字符串,但将可重复的字符保留为每个解析的子字符串 (C++ STL) 中的分隔符
- 在C++中迭代 STL 集时出现奇怪的问题<CStudent>
- 如何在 C++17 STL 并行算法中处理调度?
- 在学习数据结构之前对STL有一个了解是好的吗?
- C++ STL 排序会检查 NaN 吗?