分治算法实现两个n位的正整数相乘
分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同,最后按原问题的要求,将子问题的解逐层合并构成原问题的解,快速排序算法便是基于分治策略的一种排序方法。
这里要讲的是利用分治算法来实现两个n位的正整数相乘:
具体思路
- 给定两个均为n位的十进制正整数x、y,将其拆分为左右各一半的xl、xr、yl、yr。具体表示如下: x = xl*10^(n/2) + xr, y = yl*10^(n/2) + yr。例如12345=123*10^(5/2)+45。
- x*y=[xl*10^(n/2) + xr]*[yl*10^(n/2) + yr]=xl*yl*10^n+(xr*yl+xl*yr)*10^(n/2)+xr*yr
所以x*y的问题就转化为4个规模较小的子问题,这些子问题相互独立且性质相同,符合分治策略,但转化后的时间复杂度为T(n) = 4 * T(n / 2) + θ(n)
通过master定理可以求得 T(n) = θ(n ^ 2),并未有丝毫优化!
但伟大的数学家高斯发现xr*yl+xl*yr=(xl+xr)(yl+yr)-xl*yl-xr*yr,这样就可以将x*y**分解成关于3个乘积的子问题*,即x*y=[xl*10^(n/2) + xr] * [yl*10^(n/2) + yr] = xl*yl*10^n + [(xl+xr) * (yl+yr) - xl*yl - xr*yr] * 10^(n/2) + xr*yr。这样时间复杂度T(n) = 3 * T(n / 2) + θ(n),通过master定理求得,T(n) = O(n^log2(3) ) = O(n^1.59 )
伪代码实现
function DC_Multiply(x,y,n)
Input: positive integers x and y and the bits of them
Otput: Their product
if n = 1: return x*y
xl, xr = leftmost [n/2], rightmost [n/2] bits of x
yl, yr = leftmost [n/2], rightmost [n/2] bits of y
pro1 = DC_Multiply(xl, yl, (n+1)/2)
pro2 = DC_Multiply(xr, yr, n/2)
pro3 = DC_Multiply(xl+xr, yl+yr)
return p1*10^[2*(n/2)]+(p3-p1-p2)*10^(n/2)+p2
完整C++代码实现
#include <iostream>
#include <cmath>
#include <cstdlib>
// 分治算法实现两个n位的正整数相乘
using namespace std;
// 简单起见,x和y均为n位的正整数,n为奇偶均可
int DC_Multiply(int x, int y, int n) {
int xl, xr, yl, yr;
int pro1, pro2, pro3;
if (n == 1) {
return x*y;
} else {
int temp = pow(10, n/2);
xl = x / temp;
xr = x % temp;
yl = y / temp;
yr = y % temp;
pro1 = DC_Multiply(xl, yl, (n+1)/2);
pro2 = DC_Multiply(xr, yr, n/2);
pro3 = DC_Multiply(xl+xr, yl+yr, (n+1)/2);
return (pro1 * pow(10, 2*floor(n/2)) + (pro3-pro1-pro2) * pow(10, n/2) + pro2); //pro1对应相乘的10的幂次要注意
}
}
int main() {
string sx, sy;
int x, y;
cout << "分治算法实现两个相同位数的正整数相乘:" << endl;
cout << "请输入正整数x:";
cin >> sx;
cout << "请输入正整数y:";
cin >> sy;
int length = sx.length();
// string转int类型函数
x = atoi(sx.c_str());
y = atoi(sy.c_str());
cout << x << "*" << y << "==" << DC_Multiply(x, y, length) << endl;
return 0;
}
运行结果截图:
反思与总结
首选是对分治策略更进一步的理解,再者就是优化就在身边,即使是两个数相乘也一样能找到更为优化的解法,不过美中不足的是必须确保两个数均为n位数,除此之外,对string转int类型又有了一定的温习,这样就不至于再傻乎乎的要求用户输入数字的位数。