Here is my attempt at a STL compatible solution in the C ++ 11 standard:
#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; }
In live on coliru mode,
he gives this as a final conclusion:
36 0
I believe this indicates correctness:
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 = 36 ((1 - 2) - (3 - 4)) - ((5 - 6) - (7 - 8)) = ((-1) - (-1)) - ((-1) - (-1)) = 0 - 0 = 0
Note that the βcorrectβ behavior in non-power ranges is a bit ambiguous. In my version, what I am doing is always sharing a range of length n at the first power equal to two less than n . Therefore, if you give it a strength of two, you always get a perfectly balanced binary tree. If you give 6, you will get something like this:
/\ /\ /\ /\ /\
However, nothing that says always dividing by two is also wrong, so you get a tree structure like this
/\ /\ /\ /\ /\
So, with IMO, your question is a little vague. Maybe it doesn't matter to you if the depth is O(log n) ?