人人都能学会的编程入门课
胡光
原百度高级算法研发工程师
19410 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 38 讲
开篇词 (1讲)
人人都能学会的编程入门课
15
15
1.0x
00:00/00:00
登录|注册

14 | 框架思维(上):将素数筛算法写成框架算法

你好,我是胡光,咱们又见面了。
上一节呢,我们提到了一个词,叫做“算法思维”,就是用算法去解决问题的思维方式,并且说明了算法思维有别于我们通常所说的“算法”。那么如何锻炼算法思维呢?
今天我要说的这个方法,就叫做“照猫画虎”。什么意思呢?如果我们把一个个具体的算法称之为猫,而每个具体算法中所能锻炼的“算法思维”就是那只虎。也就是说,我们可以通过学习一些简单具体的算法,来总结一些重要的算法思维。
接下来的两节中,我先带你锻炼的是算法思维中的“框架思维”,所谓框架思维就是将一个具体的算法学成一个框架,变成一个可以解决多个问题的利器。废话不多说,开始今天的课程吧。

今日任务

在开始今天的学习之前,先让我们来看看今天这 10 分钟的任务吧。这个任务很简单,就是求 1 万以内所有素数的和。
素数,也叫做质数,就是只能被 1 和其本身整除的数字。举例说,30 以内的素数依次是:2、3、5、7、11、13、17、19、23、29,这几个数字相加之和,等于 129。
而与素数相对的概念,就是合数,它指的是除了能被 1 和其本身整除以外,还可以被其他数字整除的数字。你可以简单理解为合数是由若干个素数相乘得到的数字,也就是说一个合数,一定能被某个素数整除。例如,6 就是合数,能被 2 和 3 这两个素数整除。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了素数筛算法的框架思维及其在算法思维中的重要性。文章首先阐述了素数的概念和素数筛算法的思想和流程,通过示例代码演示了如何使用素数筛算法找出指定范围内的素数。文章强调了素数筛算法的正确性,并通过数学归纳法的证明展示了其有效性。此外,文章还提供了关于素因子分解程序正确性证明的思考题,以及使用素数筛算法求解1万以内所有素数的和的示例代码。最后,文章总结了素数筛算法的框架思维,强调了理解算法代码的重要性,并鼓励读者熟记素数筛的算法框架。整体而言,本文内容简洁清晰,适合读者快速了解框架思维和素数筛算法的基本原理。文章内容涵盖了算法思维的重要概念,对于算法学习者具有一定的指导意义。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《人人都能学会的编程入门课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(18)

  • 最新
  • 精选
  • 🤪HappyJoo
    老师请问一下,您觉得有必要把这几个在文中出现的代码“背”下来吗?因为在看代码的时候总觉得好像会写,但是实际上去写不看您的代码的时候,就写不出来了。身为一个合格的程序员,应该要有能力,可以脱离您的教程,独自根据题目要求,写出代码吧?

    作者回复: 你可以把代码的学习看成两部分,第一部分是熟练程度,第二部分是逻辑性,其中想要提升熟练程度,只有多敲多打,我现在还没有找到太好的办法,让人不写一行代码,就学会编程。-_-|||

    2020-02-16
    5
  • 🤪HappyJoo
    1,for (int i = 2; i <= MAX_N; i++) { sum += i * (1 - prime[i]); } 2,for (int i = 2; i <= MAX_N; i++) { if (!prime[n]) sum += i; } 老师你好,突然想问一下,这里哪个效率更高呢?我猜是第二个嘿嘿嘿~

    作者回复: 这个要是单纯来说的话,我认为,应该是第二个效率高一些。因为第二个使用了 if 分之条件,就会触发 CPU 的分之预测动作,只要有预测成功的情况,对于执行效率来说的话就是正向收益。

    2020-03-06
    3
  • 信念
    i * i <= MAX_N 这个判断条件真是学到了

    作者回复: d(^_^o)

    2020-06-01
    2
  • 罗耀龙@坐忘
    茶艺师学编程 1、思考题 (1)反证一下,如果n可以被整除,但i就是合数--这样的情况完全有可能。然而合数是素数的倍数,就是说被选到的这个i是对应的素因子后面,问题是程序是从前往后一个一个地检验过来的,那么这个i怎么就直接跳到后面呢?所以这里就矛盾了。 因此按照程序规定的从前往后,只要n可以被i整除,i就一定是素数。 (2)我做不出来…… 2、课文提到的欧拉筛替换挑战 我也是参考别人的…… // 欧拉筛素数(带视窗的) void Euler() { for (int i = 2; i <= MAX_N; i++) { if(p[i] == 0) p[PrimeNum++] = i;//这里把p数组按顺序(2-10000)“刷”上数字 for (int j = 2; j <= MAX_N; j++) { if(i * p[j] > MAX_N)// 在用i刷数字的时候,用数组p来框定范围:i*p[j]<10000 break; p[i * p[j]] = 1;//在上用 i * p[j]来圈定就算范围,在这里当做P数组的指针来标记合数(指针为合数的话对应的数组值为1) if(i % p[j] == 0)//如果i能被p[j]整除(倍数),那这个数就跳过 break; } } return ; } int main() { Euler(); int sum = 0; for (int i = 0; i <= PrimeNum; i++) { printf("%d\n", p[i]); sum += p[i]; } printf("\n一万以内的素数和:%d\n", sum); return 0; } 这里有个疑问,我这里看到的欧拉筛出来的就是素数,那么合数标记p[i * p[j]] = 1怎么就不见呢?是因为下面的break直接让“1”消失了吗?

    作者回复: 能有这样的思考很不错。d(^_^o) 关于你的疑问,要理解一点,合数 N = p * M,其中 p 是 N 中最小的素数,也就是程序中的 p[j],M 就是程序中的 i。如果不 break,继续向后枚举 N=i * p[j] 的话, p[j]就不是 N 中最小的素因子了。

    2020-06-28
    1
  • 宋不肥
    欧拉法: #include <stdio.h> #define MAX_N 10000 int PrimeNum=2; int p[MAX_N + 1] = {0}; // 欧拉筛素数 void Euler() { for (int i = 2; i <= MAX_N; i++) { if(p[i] == 0) p[PrimeNum++] = i; for (int j = 2; j <= MAX_N; j++) { if(i * p[j] > MAX_N) break; p[i * p[j]] = 1; if(i % p[j] == 0) break; } } return ; } int main() { Euler(); int sum = 0; for (int i = 0; i <= PrimeNum; i++) { sum += p[i]; } printf("%d\n", sum); return 0; }

    作者回复: 可以的!d(^_^o),再试着把因子个数公式加到这个框架中。就更好了!

    2020-02-20
    1
  • 宋jia wen
    老师 void print_num(int num , int *flag) 为什么加“*”,直接写flag 不行吗

    作者回复: 不行,输出的过程中需要有一个类似全局变量的东西记录是否输出过,这个值需要记录在flag变量中,如果没有*,就起不到记录的效果。

    2020-02-18
    1
  • 在声明素数筛 prime 数组的大小时为什么要加上5呢?这个5是怎么得到的?

    作者回复: 哦哦哦,只是空间稍微开大一点点。个人编码习惯。

    2020-02-15
    1
  • 乘坐Tornado的线程魔法师
    内容干货慢慢,理解思想最重要。 P.S. 小编,你看如果这样设定标题捏? "将素数筛选算法写成框架算法""

    作者回复: d(^_^o)

    2020-02-15
    2
    1
  • Noya
    #include <iostream> using namespace std; const int N = 1e6 + 10; int n; int st[N]; void init_prime(int n) { for (int i = 2; i <= n; i++) { if (st[i]) continue; for (int j = i * 2; j <= n; j += i) { if (!st[j]) st[j] = 1; } } return; } int main(void) { scanf("%d", &n); init_prime(n); for (int i = 2; i <= n; i++) { if (!st[i]) { if (i > 2) printf(" "); printf("%d", i); } } return 0; }

    作者回复: d(^_^o)

    2020-05-20
  • 小风
    老师,那个flag初始为0,中间也没看到有变化啊,为什么判定条件*flag==1成立呢?

    作者回复: 注意观察代码的第7行,flag 的值是有变化的。

    2020-05-07
收起评论
显示
设置
留言
18
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部