C++ 如何将递归代码更改为迭代形式
我在下面实现了一个简单的FFT(忽略最终的缩放):C++ 如何将递归代码更改为迭代形式,c++,algorithm,recursion,iteration,fft,C++,Algorithm,Recursion,Iteration,Fft,我在下面实现了一个简单的FFT(忽略最终的缩放): typedef复合基; 向量w; int-FFTN=1024; void fft(矢量和fa){ int n=fa.size(); 如果(n==1)返回; 半整数=(n>>1); 向量奇(半),偶(半); 对于(inti=0,j=0;i1); int半=1; 而(一半以下是我的实现: typedef complex<double> Data; const double PI = acos(-1); // Merges [low,
typedef复合基;
向量w;
int-FFTN=1024;
void fft(矢量和fa){
int n=fa.size();
如果(n==1)返回;
半整数=(n>>1);
向量奇(半),偶(半);
对于(inti=0,j=0;i1);
int半=1;
而(一半以下是我的实现:
typedef complex<double> Data;
const double PI = acos(-1);
// Merges [low, (low + high) / 2) with [(low + high) / 2, high) parts.
void merge(vector<Data>& b, int low, int high) {
int n = high - low;
Data cur(1), mul(cos(2. * PI / n), sin(2. * PI / n));
for (int i = low; i < low + n / 2; i++) {
Data temp = b[i + n / 2] * cur;
b[i + n / 2] = b[i] - temp;
b[i] = b[i] + temp;
cur = cur * mul;
}
}
// Computes FFT for the vector b.
void do_fft(vector<Data>& b) {
int n = b.size();
int hi = 0;
while ((1 << hi) < n)
hi++;
hi--;
// Permutes the input vector in a specific way.
vector<int> p(n);
for (int i = 0; i < n; i++)
for (int b = hi; b >= 0; b--)
if (i & (1 << b))
p[i] |= (1 << (hi - b));
vector<Data> buf(n);
for (int i = 0; i < n; i++)
buf[i] = b[p[i]];
copy(buf.begin(), buf.end(), b.begin());
for (int h = 2; h <= n; h *= 2)
for (int i = 0; i < n; i += h)
merge(b, i, i + h);
}
typedef复杂数据;
常数双PI=acos(-1);
//将[低,(低+高)/2)与[(低+高)/2,高)部件合并。
无效合并(矢量和b、整数低、整数高){
int n=高-低;
数据cur(1)、mul(cos(2.*PI/n)、sin(2.*PI/n));
对于(int i=low;i if(i&(1这并不能提供一个确切的解决方案。但可能有助于解决将递归算法转换为迭代算法的类似问题。递归在系统中通过堆栈实现。对方法的每次递归调用都会将以下信息推送到堆栈上:
功能参数
局部变量
回信地址
如果程序员可以使用堆栈+while循环
执行上述操作,我们可以将递归算法实现为迭代算法
用于调用递归函数的参数
调用现在将被推送到堆栈
然后我们进入一个while循环(直到堆栈为空),同时弹出
来自堆栈的参数(LIFO)和调用核心逻辑
继续将更多参数推送到堆栈,并重复(2),直到堆栈为空
使用上述方法进行迭代阶乘计算的代码示例
int coreLogic( int current, int recursiveParameter ) {
return current * recursiveParameter ;
}
int factorial( int n ) {
std::stack<int> parameterStack ;
int tempFactorial = 1;
//parameters that would have been used to invoke the recursive call will now be pushed to stack
parameterStack.push( n );
while( !parameterStack.empty() ) {
//popping arguments from stack
int current = parameterStack.top();
parameterStack.pop();
//and invoking core logic
tempFactorial = coreLogic( tempFactorial, current );
if( current > 1 ) {
//parameters that would have been used to invoke the recursive call will now be pushed to stack
parameterStack.push( current - 1 );
}
/*
*if a divide and conquer algorithm like quick sort then again push right side args to stack
* - appers case in question
*if( condition ) {
* parameterStack.push( args );
*}
*/
}
return tempFactorial;
}
int-coreLogic(int-current,int-recursiveParameter){
返回电流*递归参数;
}
整数阶乘(整数n){
std::stack参数stack;
因式阶乘=1;
//用于调用递归调用的参数现在将被推送到堆栈中
参数stack.push(n);
而(!parameterStack.empty()){
//从堆栈中弹出参数
int current=参数stack.top();
参数stack.pop();
//调用核心逻辑
tempFactorial=核心逻辑(tempFactorial,当前);
如果(当前>1){
//用于调用递归调用的参数现在将被推送到堆栈中
参数stack.push(当前值-1);
}
/*
*如果使用像快速排序这样的分治算法,则再次将右侧参数推送到堆栈
*-上诉案件
*如果(条件){
*参数stack.push(args);
*}
*/
}
返回因子;
}
我要做的第一件事是使函数“更递归”
我们反复做奇偶运算
a[e] b[o] a[e] d[o]
a[ee] b[oe] a[eo] d[oo]
然后循环进行奇偶运算
a[e] b[o] a[e] d[o]
a[ee] b[oe] a[eo] d[oo]
这些集合的大小为1。它们单独存在,然后我们将奇数和偶数合并
现在我们来看8。在两次递归之后,元素由以下人员“拥有”:
0[ee] 1[oe] 2[eo] 3[oo] 4[ee] 5[oe] 6[eo] 7[oo]
第三次之后:
0[eee] 1[oee] 2[eoe] 3[ooe] 4[eeo] 5[oeo] 6[eoo] 7[ooo]
如果我们反转这些标签,并调用e
0
和o
1
,我们得到:
0[000] 1[001] 2[010] 3[011] 4[100] 5[101] 6[110] 7[111]
这是二进制计数。第一位被丢弃,现在相等的元素在第二个到最后一个递归调用中合并
然后丢弃前两位,并组合具有匹配的最后一位的元素
我们可以不看比特,而是看每个组合的开始,以及步幅
第一个组合是步长,等于数组长度(每个元素1个)
第二个是长度/2,第三个是长度/4
这一直持续到步幅1
要合并的子阵列数等于步幅长度
所以
其中,fft\u过程
基于:
int fact = FFTN/n;
for (int i=0;i<half;i++){
fa[i] = fa[stride*2*i] + fa[stride*2+i+stride] * w[i * fact];
fa[i + half] = fa[stride*2*i] - fa[stride*2+i+stride] * w[i * fact];
}
int-fact=FFTN/n;
对于(int i=0;我帮个忙,你能少用逗号运算符吗?多用大括号吗?第二,你为什么想要一个迭代版本?@Yakk谢谢你的建议。我更改了编码格式。我确实想比较一下速度,因为据说递归有时会因为被调用的子函数存储在堆栈中而变慢。主要问题是你调用了您的迭代两次,使得在迭代版本中很难实现此实现。它可能无法回答您的问题,但我使用的是这个简单的FFT实现,它非常快(算法第1章-附录B):注意,在对原始版本中的元素进行数学运算之前,您会递归。这意味着第一个“数学”完成是在最深的递归上。最深的递归对应于迭代版本中的长“步幅”。在迭代版本中,您首先对短步幅版本进行计算。
0[000] 1[001] 2[010] 3[011] 4[100] 5[101] 6[110] 7[111]
for(size_t stride = n; stride = stride/2; stride!=0) {
for (size_t offset = 0; offset != stride; ++offset) {
fft_process( array+offset, stride, n/stride );
}
}
int fact = FFTN/n;
for (int i=0;i<half;i++){
fa[i] = fa[stride*2*i] + fa[stride*2+i+stride] * w[i * fact];
fa[i + half] = fa[stride*2*i] - fa[stride*2+i+stride] * w[i * fact];
}
void fft_process( base* fa, size_t stride, size_t n ) {
int fact = FFTN/n; // equals stride I think! Assuming outermost n is 1024.
for (int i=0;i<half;i++){
fa[i] = fa[stride*2*i] + fa[stride*2+i+stride] * w[i * fact];
fa[i + half] = fa[stride*2*i] - fa[stride*2+i+stride] * w[i * fact];
}
}