【C语言】认识快速幂 学习笔记

  

UP主五点七边《快速幂都能做什么?小小的算法也有大大的梦想》(BV16Z4y1M7y1)这期视频做的太好了,看完我总算是理解快速幂是什么意思了,为了巩固知识点自己码了一遍学习笔记:

【声明:本文中统一用n代指底数,p代指指数,文中代码有一些是伪代码】

(一)引入

如果我们要计算n^64,最一般的朴素算法是:

repeat(64-1) //repeat指重复执行的次数

{

       sum+=sum*n;

}

显然这样的时间复杂度非常之高。为了优化算法,我们使用快速幂算法:

快速幂算法的核心思想是:n^p = n^(p1 + p2 + ... + pk)= n^p1 * n^p2 *...* n^pk,其中p1、p2、...、pk都是2的整数次方,也就是:把幂分解成2的幂的和。

举个例子:

求n^64,我们就把它分解为求n^(1+1+2+4+8+16+32),

求n^105,我们就把它分解为求n^(1+8+32+64)。

(二)求“分解幂”

那接下来的问题便转化成了:如何把一个数分解成2的幂的和,在这里我们把这些 “2的幂” 叫作 “分解幂”。我们以n^105为例子,首先分别写出105、1、8、32、64的二进制形式:

105  1 1 0 1 0 0 1

—————————

  1    0 0 0 0 0 0 1

  8    0 0 0 1 0 0 0

 32   0 1 0 0 0 0 0

 64   1 0 0 0 0 0 0

通过观察我们发现,105的二进制数有4个1,其他四个数的二进制数各有一个1,且它们处在的位置和105一一对应。

我们再对这四个1的位置进行进一步观察:

位    7 6 5 4 3 2 1

—————————

105  1 1 0 1 0 0 1

—————————

  1    0 0 0 0 0 0 1

  8    0 0 0 1 0 0 0

 32   0 1 0 0 0 0 0

 64   1 0 0 0 0 0 0

可以发现,105的四个1分别处在第1、第4、第6、第7位上,其余位都是0。

到这里,我们就能大概摸出快速幂算法的工作方式了:

步1:将105转化为二进制数;

步2:从二进制数的第1位开始往高位遍历,遇到1就确定这个位对应的“分解幂”,遇到0就跳过不管;

步3:经过了前两个步骤,已经将n^105成功转化为若干个“n^分解幂”的积。

 

(三)代码实现

那么我们怎么用代码来实现上面的步骤呢?

1、获取底数n和指数p。不用多说:

get(n);

get(p);

2、遍历指数p的二进制数的每一位。C/C++使用位运算符“ >> ”,意思是将其二进制数向右移一位,也就是达到了第1位向高位遍历的效果:

p>>=1;

拿一个二进制数直观地演示一下,[ ]代表当前遍历到的数:

       0  1  0  1 [0] 跳过

p>>=1;

       0  0  1  0 [1] 取分解幂

p>>=1;

       0  0  0  1 [0] 跳过

p>>=1;

       0  0  0  0 [1] 取分解幂

p>>=1;

       0  0  0  0 [0] 跳过

3、判断遍历到的该位是否为1。使用位运算符“ & ”:

p&1 = 1 :即该位上是1

p&1 = 0 : 即该位上是0

4、判断遍历结束。由于我们是使用移位运算符,所以当p的所有1都被遍历完之后,p也就变成0,此时遍历即可结束:

       0  0  0  0 [0] 跳过

遍历结束;

5、综上所述,用C写出的快速幂函数代码如下:

long long fastpower(long long n,long long p)
{
    long long ans=1;
    while(p)
    {
        if(p&1)
        {
            ans=ans*n;
        }
        n=n*n;
        p>>=1;
    }
    return ans;
}

 

(四)结论

如果分别按朴素算法和快速幂算法来求2^60的话,可以发现朴素算法需要的运算次数为60,而

快速幂算法的运算次数为6。所以,快速幂算法的意义在于将求某数n次方的时间复杂度从O(p)

降为了O(log₂p)!(log₂60 ≈ 6)

 

感谢我的好同学帮我一起完善本博客,如有错漏还敬请指出!快速幂算法的具体应用篇幅还是比较长的,找时间再单独写一篇笔记吧。大家也可以关注下up主五点七边,他的动画很简洁明了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SeeChell

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值