非递归的快速傅立叶变换
快速傅里叶变换没什么好说的, 只是需要注意避免递归.
避免递归
上面那个递归版本的FFT实际上常数很大,因为要复制数组。我们观察一下递归树,假设这是一个长度为8的多项式。
+===============================================+
| 000 001 010 011 100 101 110 111 |
+-----------------------------------------------+
| 000 010 100 110 | 001 011 101 111 |
+-----------------------------------------------+
| 000 100 | 010 110 | 001 101 | 011 111 |
+-----------------------------------------------+
| 000 | 100 | 010 | 110 | 001 | 101 | 011 | 111 |
+===============================================+
实际上,从叶子往上做的话就是把每个数的二进制位颠倒过来。
1 struct Complex 2 { 3 double real, imag; 4 Complex(const double r = .0, const double i = .0): real(r), imag(i) { } 5 }; 6 const Complex ZERO(.0, .0); 7 inline Complex operator+(const Complex& lhs, const Complex& rhs) { return Complex(lhs.real+rhs.real, lhs.imag+rhs.imag); } 8 inline Complex operator-(const Complex& lhs, const Complex& rhs) { return Complex(lhs.real-rhs.real, lhs.imag-rhs.imag); } 9 inline Complex operator*(const Complex& lhs, const Complex& rhs) { return Complex(lhs.real*rhs.real-lhs.imag*rhs.imag, lhs.real*rhs.imag+lhs.imag*rhs.real); } 10 inline int bit_reverse(const int x, const int n) 11 { 12 int res = 0; 13 for (int i = 0; i < n; ++i) 14 res |= (x>>i&1)<<(n-i-1); 15 return res; 16 } 17 void fft(Complex y[], const Complex a[], const int n, const int rev) 18 { 19 const int len = 1<<n; 20 for (int i = 0; i < len; ++i) y[i] = a[bit_reverse(i, n)]; 21 for (int d = 1; d <= n; ++d) 22 { 23 const int m = 1<<d; 24 const Complex wn(std::cos(2*PI/m*rev), std::sin(2*PI/m*rev)); 25 for (int k = 0; k < len; k += m) 26 { 27 Complex w(1., .0); 28 for (int j = 0; j < m/2; ++j) 29 { 30 const Complex u = y[k+j], t = w*y[k+j+m/2]; 31 y[k+j] = u+t, y[k+j+m/2] = u-t; 32 w = w*wn; 33 } 34 } 35 } 36 if (rev == -1) 37 for (int i = 0; i < len; ++i) y[i].real /= len, y[i].imag = .0; 38 } 39 void convolution(Complex c[], Complex a[], Complex b[], const int la, const int lb) 40 { 41 static Complex tmp1[MAXN], tmp2[MAXN]; 42 int n = 0, len = 1<<n; 43 for (; len < 2*la || len < 2*lb; ++n) len <<= 1; 44 std::fill(a+la, a+len, ZERO); 45 std::fill(b+lb, b+len, ZERO); 46 fft(tmp1, a, n, 1); 47 fft(tmp2, b, n, 1); 48 for (int i = 0; i < len; ++i) tmp1[i] = tmp1[i]*tmp2[i]; 49 fft(c, tmp1, n, -1); 50 }
posted on 2013-06-12 09:57 初昱天殷HatsuakiraTenan 阅读(338) 评论(0) 编辑 收藏 举报