乘法的本质可以理解为重复加法的过程

大邳草民 2024-04-04 18:35:44
加精

在使用埃氏筛选法求质数中,遇到一些不太好理解的地方。

完整代码链接如下:

http://t.csdnimg.cn/f1v8u

主要代码片段如下:

 for (int i = 2; i * i <= n; i++) { // 从2开始遍历到根号n
                if (isPrime[i]) { // 如果当前数是素数
                    for (int j = i * i; j <= n; j += i) { // 将当前素数的倍数标记为非素数
                        isPrime[j] = false;
                    }
                }
            }

以下是个人的一些理解: 

1. 首先对于 for (int i = 2; i * i <= n; i++)中的 i * i <= n 的理解:

这里使用了优化技巧,因为如果一个数n不是素数,那么它的最小质因数肯定小于等于根号n。所以只需要遍历到根号n即可。

2. 在 for (int j = i * i; j <= n; j += i)中 int j = i * i 的作用是什么?

int j = i * i 的作用是从 i 的平方开始标记非素数。

但又为什么是从平方开始?

这是因为在 i 的平方之前的 i 的倍数已经被之前的素数标记过了,所以我们只需要从 i 的平方开始标记即可,避免重复标记。

举个例子来说明:

- 当 i = 2 时,我们从 4 开始标记非素数,因为 2 的倍数 4 已经被标记为非素数了。
- 当 i = 3 时,我们从 9 开始标记非素数,因为 3 的倍数 6 和 9 已经被之前的素数(2)标记为非素数了。

这样做的好处是可以避免重复标记,提高算法的效率。因此, int j = i*i  是为了确保我们从 i 的平方开始标记非素数,而不是从 i 的倍数开始,避免重复标记。

3. 对于for (int j = i * i; j <= n; j += i) 中为什么是 j = j + i ,而不是 j = j * i。

将当前的倍数标记为非素数,更新条件表达式应该是使用乘法表示倍数吧。

但是请看下面示例:

以2的倍数为例

加法:

2+2=4

2+2+2=6

2+2+2+2=8

2+2+2+2+2=10

乘法:

2*2=4

2*2*2=8

2*2*2*2=16

2*2*2*2*2=32

如果我们使用 j = j * i 来递增,那么 j 的增长速度会过快, 则会跳过某些 j 的倍数,导致未能正确标记所有的非素数。

对此乘法的本质可以理解为重复加法的过程。

这样就可以理解: 2的倍数是不断的加2,而不是一味的乘2。

或者是 2*2, 2*3,2*4 ...

所以以上代码中还是使用加法比较合适,如果使用乘法的话,需要再嵌套个循环吧?

这里没有去验证,感觉需要花费一点时间,等闲的没事再去验证吧。

 

所以以上的代码片段是进行优化过的。

未优化的代码片段如下:

for (int i = 2; i <= n; i++) {
    if (isPrime[i]) {
        for (int j = i + i; j <= n; j += i) {
            isPrime[j] = false;
        }
    }
}
...全文
340 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

1

社区成员

发帖
与我相关
我的任务
社区描述
Sharing of learning or learning experience.
学习笔记 个人社区
社区管理员
  • 大邳草民
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧