我需要转换这段python代码以达到速度目的。 r和n是用户定义的整数变量。
该函数应该生成具有以下条件的所有列表:
listSum = n,length = r,值(替换)在[0,1,2,...,n]
def recurse(r,n):
if r == 1:
yield [n]
return
for i in range(n+1):
for j in recurse(r-1,n-i):
yield [i]+j
我尝试使用静态变量,但它们在不正确的时间递增。我试图从main函数更改我需要的变量(r,n和i)并将它们传递给我的生成器等效函数,但是这个解决方案似乎不适用于r和n的不同初始值。我正在开发一个没有安装Boost的系统,我没有安装它的系统权限。那么如何将递归python列表生成器转换为C ++?
当我迭代recurse(r=3, n=4)
时,我得到:
[0, 0, 4]
[0, 1, 3]
[0, 2, 2]
[0, 3, 1]
[0, 4, 0]
[1, 0, 3]
[1, 1, 2]
[1, 2, 1]
[1, 3, 0]
[2, 0, 2]
[2, 1, 1]
[2, 2, 0]
[3, 0, 1]
[3, 1, 0]
[4, 0, 0]
答案 0 :(得分:2)
首先,您可以查看this thread以获取有关算法的更多信息。你会发现你生成的列表数量是(n + r-1)C(r-1),这可能会有所帮助。有多种方法可以翻译这段代码,但我会给你两个。
首先,在C ++中,生成器模式并不常见。根据您的要求,大多数情况下您希望在开始时为所有此输出实际分配内存,计算日期,然后返回完整矩阵。其次,你无法在C ++中以这种方式递归,你会很快破坏你的堆栈。所以你需要一个算法的迭代版本。以下是如何做到这一点(使用迭代器,就像我们在C ++中所喜欢的那样)。
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <boost/math/special_functions/binomial.hpp>
#include <boost/numeric/conversion/cast.hpp>
using namespace std;
vector<vector<size_t>> gen_matrix(unsigned int n, unsigned int r)
{
vector<vector<size_t>> res;
if(r < 1) return res;
// reserve memory space
// this will throw positive_overflow if size is too big to be represented as size_t
// this can also throw out_of_memory if this is size_t-representable but memory is too small.
double result_size = boost::math::binomial_coefficient<double>(n + r - 1, r - 1);
res.reserve(boost::numeric_cast<size_t>(result_size));
vector<size_t> current(r, 0);
current.front() = n;
res.push_back(current);
vector<size_t>::iterator inc = next(current.begin()); // what we increment
while(inc != current.end())
{
while(current.front() != 0)
{
(*inc)++;
current.front()--;
res.push_back(current);
while(prev(inc) != current.begin())
inc--;
}
swap(current.front(), *inc++);
}
return move(res);
}
int main()
{
auto r = gen_matrix(6, 4);
for(auto v : r)
{
copy(v.begin(), v.end(), ostream_iterator<int>(cout, ", "));
cout << endl;
}
}
注意:与您的示例相比,生成反向,因为这种方式在使用C ++容器时更加自然(因为迭代器与容器的比较< EM>端()的)。此外, boost 部分用于预先计算大小并提前引发异常以避免内存耗尽(并保留内存以避免重新分配)。这不是强制性的,您也可以对此部分进行评论(风险自负^^)。
但你的需要的发电机,比如,你要编写一个程序,将写整数名单万亿个字节中保存的地图,盘大文件(当然,谁知道?)。或者你可能希望能够计算n = 100,r = 80,跳过2或3百万个向量,然后选择一堆。或者你只是想避免大量使用内存。好吧,无论如何,发电机可能会派上用场;在这里。
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <stdexcept>
#include <boost/math/special_functions/binomial.hpp>
#include <boost/numeric/conversion/cast.hpp>
struct sum_list_generator
{
typedef vector<unsigned int> result_type;
sum_list_generator(unsigned int n, unsigned int r):
current(r, 0),
inc(current.begin())
{
if(inc != current.end()) *inc++ = n;
}
result_type operator()()
{
if(inc == current.end())
throw out_of_range("end of iteration");
result_type res = current;
if(current.front() == 0)
swap(current.front(), *inc++);
if(inc != current.end())
{
(*inc)++;
current.front()--;
if(current.front() != 0)
while(prev(inc) != current.begin())
inc--;
}
return move(res);
}
// helper function : number of outputed vectors
static size_t count(unsigned int n, unsigned int r)
{
return boost::numeric_cast<size_t>(
boost::math::binomial_coefficient<double>(n + r - 1, r - 1)
);
}
private:
result_type current;
result_type::iterator inc;
};
int main()
{
sum_list_generator g(6, 4);
try
{
while(true)
{
auto v = g();
copy(v.begin(), v.end(), ostream_iterator<int>(cout, ", "));
cout << endl;
}
}
catch(out_of_range const&) {}
}
注意:再次计数成员函数可以被删除。此外,您通常避免在C ++中的预期执行路径上抛出异常(而不是python)。这里的生成器可用于填充其他一些结构,如果您的参数选择得当,它就不会抛出。如果你试图使用它太多,当然会抛出超出范围。最终,捕捉异常并像在这里一样沉默它是非常糟糕的设计 - 这只是一个例子,你可以用来尝试一些有趣的参数,如(100,80)。如果您需要完整的向量列表,count()
函数会为您提供精确的边界:使用它。
答案 1 :(得分:0)
回调函数通常可以作为迭代器使用:
#include <functional>
#include <iostream>
// manipulates the memory at `dest`, and calls `doNext()` each time it contains a new set of data
void recurseHelper(int r, int n, std::function<void()> doNext, int* dest) {
if(r == 1) {
*dest = n;
doNext();
}
else for(int i = 0; i <= n; i++) {
*dest = i;
recurseHelper(r-1, n-i, doNext, dest + 1);
}
}
void recurse(int r, int n, std::function<void(int*)> f) {
int dest[r];
recurseHelper(r, n, [&] () {
f(dest);
}, dest);
}
int main() {
recurse(3, 4, [] (int* i) {
std::cout << i[0] << i[1] << i[2] << std::endl;
});
return 0;
}