快速求幂算法
2013-04-07 23:27
225 查看
我们知道在数学表达式中pow(x, n)表示求x^n的幂。一般情况下,如果我们要写一个程序的话,最简单的程序可能是这样的:
[cpp] view
plaincopy
int pow(int x, int n){
int result = 1;
while (n != 0){
result = result *x;
n = n -1;
}
return result;
}
通过使用如上的程序,2^4 = 2 * 2 * 2 * 2,在程序中做了4-1=3次乘法,但是有没有更高效的算法来减少乘法的次数呢。
答案是肯定的。
我们知道
2^9 = 2^4 * 2^4 * 2
2^8 = 2^4 * 2^4
2^7 = 2^3 * 2^3 * 2
2^6 = 2^3 * 2^3
……
我们发现了什么?
x^n = x^(n/2) * x^(n/2) (n为偶数)
x^n = x^(n/2) * x^(n/2) * n (n为奇数);
这样的话我们就可以使用递归的方法将问题化为一半一半的解法。(divide and conquer)
程序如下:
[cpp] view
plaincopy
int pow2(int x, int n){
if (n == 1) return x;
if (n == 0) return 1;
else if (n & 1)
return pow2(x, n/2) * pow2(x, n/2) * x;
else
return pow2(x, n/2) * pow2(x, n/2);
}
网上也有另外一种写法:
[cpp] view
plaincopy
int pow2(int x, int n){
if (n == 1) return x;
if (n == 0) return 1;
else if (n & 1)
return pow(x * x, n >>1)*x; //不同之处
else
return pow(x *x, n>>1); //不同之处
}
其实,这两种写法是相同,君不见pow(x, n) * pow(x, n) = pow(x*x, n)
递归有很多好处,其中之一就是代码简洁,可读性强,但是也有不好的地方,如果n的位数足够大(假设整个结果不溢出的情况),那么其使用的栈可能会产生溢出的情况。
现在既然我们已经有了一个递归的方法,那么写一个非递归的方法就水到渠成了。我们要想想如何去写这个非递归的程序了。
例如2^9 = 2^(1001) 括号里面是二进制数制。在我们做2^9乘法的时候,我们是用这样的方法来乘的:2^9 = 2^8 * 2^1
也就是只有在二进制数位上为1时乘一个2^n,而在二进制数位上为0时,则不乘。那么我们的程序就有了:
[cpp] view
plaincopy
int pow3(int x, int n)
{
int result = 1;
while (n > 0) {
if (n & 1) // n & 1 等价于 (n % 2) == 1
result *= x;
x *= x;
n >>= 1; // n >>= 1 等价于 n /= 2
}
return result;
}
程序运行良好,结果与上面的两个程序的结果相同,但是时间不知道要比上面的递归程序快多少倍呢!
[cpp] view
plaincopy
int pow(int x, int n){
int result = 1;
while (n != 0){
result = result *x;
n = n -1;
}
return result;
}
通过使用如上的程序,2^4 = 2 * 2 * 2 * 2,在程序中做了4-1=3次乘法,但是有没有更高效的算法来减少乘法的次数呢。
答案是肯定的。
我们知道
2^9 = 2^4 * 2^4 * 2
2^8 = 2^4 * 2^4
2^7 = 2^3 * 2^3 * 2
2^6 = 2^3 * 2^3
……
我们发现了什么?
x^n = x^(n/2) * x^(n/2) (n为偶数)
x^n = x^(n/2) * x^(n/2) * n (n为奇数);
这样的话我们就可以使用递归的方法将问题化为一半一半的解法。(divide and conquer)
程序如下:
[cpp] view
plaincopy
int pow2(int x, int n){
if (n == 1) return x;
if (n == 0) return 1;
else if (n & 1)
return pow2(x, n/2) * pow2(x, n/2) * x;
else
return pow2(x, n/2) * pow2(x, n/2);
}
网上也有另外一种写法:
[cpp] view
plaincopy
int pow2(int x, int n){
if (n == 1) return x;
if (n == 0) return 1;
else if (n & 1)
return pow(x * x, n >>1)*x; //不同之处
else
return pow(x *x, n>>1); //不同之处
}
其实,这两种写法是相同,君不见pow(x, n) * pow(x, n) = pow(x*x, n)
递归有很多好处,其中之一就是代码简洁,可读性强,但是也有不好的地方,如果n的位数足够大(假设整个结果不溢出的情况),那么其使用的栈可能会产生溢出的情况。
现在既然我们已经有了一个递归的方法,那么写一个非递归的方法就水到渠成了。我们要想想如何去写这个非递归的程序了。
例如2^9 = 2^(1001) 括号里面是二进制数制。在我们做2^9乘法的时候,我们是用这样的方法来乘的:2^9 = 2^8 * 2^1
也就是只有在二进制数位上为1时乘一个2^n,而在二进制数位上为0时,则不乘。那么我们的程序就有了:
[cpp] view
plaincopy
int pow3(int x, int n)
{
int result = 1;
while (n > 0) {
if (n & 1) // n & 1 等价于 (n % 2) == 1
result *= x;
x *= x;
n >>= 1; // n >>= 1 等价于 n /= 2
}
return result;
}
程序运行良好,结果与上面的两个程序的结果相同,但是时间不知道要比上面的递归程序快多少倍呢!
相关文章推荐
- Chapter_2 算法分析:快速求幂法
- 经典算法~~快速求幂的方法
- 数学:快速求幂算法
- 快速求幂算法
- LeetCode Super Pow(快速求幂算法)
- 非递归快速求幂算法
- 快速求幂算法
- 快速求幂算法
- 快速求幂算法
- 算法 二分求幂(快速取幂)
- 【算法分析与设计】快速求幂算法的分析及java实现
- 快速求幂算法
- 【算法】矩阵快速求幂
- (数据结构与算法分析 一)------快速求幂算法,Java递归实现
- 快速求幂算法
- 打造世界一流的快速大数算法库
- 常用算法模板集1【快速幂】;【归并】+【逆序对】;【快排】附md语法
- HDU4506+快速求幂
- MIT:算法导论——4.2快速排序 以及 排序算法时间复杂度分析
- 指数运算快速算法