关于算法power
一般我们遇到要实现power算法,最直接就是如下实现:
- Int power(int x, unsigned int n)
- {
- Int result = 1;
- While(n--)
- result *= x;
- return result;
- }
然而,这样计算的复杂度为O(n)
想要改进,因为 x^n = x^(n/2) * x^(n/2),所以我们想,只要计算出了x^(n/2)那么x^n也就直接得出了,于是改为如下实现:
- Int power(int x, unsigned int n)
- {
- if(n == 0)
- Return 1;
- else if(n==1)
- return x;
- else
- {
- Int r = power(x, n/2);
- If(n % 2 == 0)
- Return r*r
- Else
- Return r*r*x;
- }
- }
既然走到了这里,且我们看到了递归,那继续优化的方法就是不使用递归,因为递归不仅可能导致内存栈溢出,还会产生很多不必要的计算。
这里,我们可能会想到斐波那契数列,教科书中讲解递归总是拿这个例子,但我们知道递归并非最优。于是我们按照将斐波那契数列递归形式改为循环形式的思路,将我们当前的power函数修改为循环:
比如我们要求x^19 ,这里我们不再是采用 x^9* x^10,而是使用 x^16 * x^2 * x^1,根据19的二进制数进行计算,19的二进制为10011.
- Int power(int x, unsigned int n)
- {
- If(n == 0)
- Return 1;
- Int result = 1;
- While(n)
- {
- If(n & 1) //当该位为1,则乘到结果去
- Result *= x; //最后 result = x * x^2 * x^16
- n >>= 1;
- x *= x; //注意,这里是x*x所以是x^1, x^2, x^4, x^8,x^16
- //是成倍的上去的, x值是在不断变化的
- }
- }
于是我们理解stl中的power也就容易了:
//计算x^n
- int power(int x, unsigned int n)
- {
- if(n == 0)
- {
- return1;
- }
- else
- {
- while((n & 1) == 0) //去掉后几位的0
- {
- n>>= 1;
- x*= x;
- }
- }
- int result = x;
- n>>= 1;
- while(n != 0) //大体一样
- {
- x*= x;
- if((n & 1) != 0)
- result*= x;
- n>>= 1;
- }
- return result;
- }
//这里我们比较一下,多了一个步骤,去掉了后几位的0,大概是能够增加效率的吧!