前言
在写这篇博客之前,我浏览了很多介绍快速幂的博客,希望从中借鉴其精华,来弥补我可能有的考虑不足之处。
我发现很多的大神在描述快速幂的原理实现时都利用了二进制权值 (不知道各位小可爱对这个词儿熟悉不)。二进制权值对我来说是个新词,虽然我去了解它的时候发现它并不难理解,但我还是决定用更接地气的方法,来解释快速幂的原理及实现。
实现代码
先不说其他的,直接怼代码
int kmi(int a,int n) //a为底数,n为指数
{
int ans=1; //用于存储的结果
while(n>0)
{
if(n&1) //指数为奇数时
ans*=a;
a=a*a;
n>>=1; //指数右移
}
return ans;
}
代码中用到了位运算中的与操作运算符&和二进制运算符>>。如果你对这两个或其他的运算符不甚了解,那就点这里。接地气的方法在下面哦
算法原理
下面通过分别展现普通求幂和快速求幂的运算过程,让你直观的看到快速幂是怎么更“快”的。
以求2^11为例
-
普通算法:
211 = 2 * 210 = 4 * 29 … = 256 * 23 = 512 * 22 = 1024 * 21 = 2048。需要计算10次 -
快速算法:
211 = 2 * 45 = 8 * 162 = 8 * 2561 = 2048。只需要计算3次!!!
通过上面的例子我们可以发现,普通的算法每运算一次,底数不变,指数比原来少一。所以当求an时,就需要计算n次,故其时间复杂度为O(n)。而快速幂算法每运算一次,底数变为原来的平方,指数变为原来的二分之一(快画重点!)。所以只需要计算log2n次(当指数为1时),就可以计算出an的结果。姑其时间复杂度为O(long2n)。
总结一下:简单来说,快速幂是通过对指数的压缩来减少运算的次数的。
算法实现
总的来说,我们可以把算法的过程分为两步
- 判断指数的奇偶性,如果为奇数,就让ans=ans*度数。其中ans是用来存储结果的变量。
- 让底数变为原来的平方,即a=a*a;让指数变为原来的二分之一,即n>>1;
注意:的是循环结束的条件为n<=0,事实上当n==1时就计算出结果了,但由于位移操作放在循环尾部,所以1变成了0
有人说我写代码时不想搞&、>>这些花里胡哨的咋弄
这简单
int kmi(int a,int n)
{
int ans=1;
while(n>0)
{
if(n%2!=0) //只要能判断奇偶性,用什么方法无所谓,不过n&1要比这种效率高一点
ans*=a;
a=a*a;
n/=2;
}
return ans;
}
这个代码够实在、够接地气吧,哈哈哈
总结
快速幂算法最核心的部分就是判断指数的奇偶性和指数减半的操作,是要理解了这两点,快速幂就不难掌握了。