C++ 如何将递归代码更改为迭代形式

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,

我在下面实现了一个简单的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, (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;iif(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];
      }
    }