素数求解的N种境界
<div id="blogColumnPayAdvert">
<div class="column-group">
<div class="column-group-item column-group0 column-group-item-one">
<div class="item-l">
<a class="item-target" href="https://blog.csdn.net/m0_66769266/category_11823443.html" target="_blank" title="典型例题" data-report-click="{"spm":"1001.2101.3001.6332"}">
<img class="item-target" src="https://img-blog.csdnimg.cn/6494da2886c040a884a2a451dcf8dbcc.png?x-oss-process=image/resize,m_fixed,h_224,w_224" alt="">
<span class="title item-target">
<span>
<span class="tit">典型例题</span>
<span class="dec">专栏收录该内容</span>
</span>
</span>
</a>
</div>
<div class="item-m">
<span>25 篇文章</span>
<span>16 订阅</span>
</div>
<div class="item-r">
<a class="item-target article-column-bt articleColumnFreeBt" data-id="11823443">订阅专栏</a>
</div>
</div>
</div>
</div>
<article class="baidu_pl">
<div id="article_content" class="article_content clearfix">
<link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/kdoc_html_views-51db9abdb7.css">
<link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/ck_htmledit_views-6e43165c0a.css">
<div id="content_views" class="markdown_views prism-tomorrow-night">
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
</svg>
<p><img src="https://img-blog.csdnimg.cn/ec70c20728b74862bf38b2b8225c79b2.gif" alt="在这里插入图片描述"></p>
本期介绍🍖
主要介绍:如何快速筛查素数的方法,详细讲解了试除法和筛选法的N种境界👀。
目录🍖
前言🍖
质数(prime number)又称素数。一个大于1的自然数,除了1和它本身外,不能被其他自然数整除的数被称为素数(换句话说就是该数除了1和它本身以外不再有其他的因数)。现在有一个题目:请编写代码找出1——120之间的素数。那我们该如何编写关于这道题的较优代码呢?下面我会介绍两种类型的算法的代码,第一种为“试除法”,第二种为“筛选法”。
试除法🍖
那什么是试除法呢?通过不断试除1和本身之外的自然数来判断该数是否为素数的方法称为试除法(只要有一个自然是能够整除该数,则其就不是素数;若一个都不能整除该数,则其就是素数)。
境界1(试除从 2—(n-1) )🍖
该方法就是循环遍历所有情况,效率很差。
#include<stdio.h>
int main()
{
int i = 0;
int count1 = 0;//循环的次数
int count2 = 0;//素数的个数
printf("1——120之间素数为:\n");
for (i = 2; i <= 120; i++)
{
int j = 0;
for (j = 2; j < i; j++)//试除除了1和它本身之外所有的数
{
count1++;
if (i % j == 0)
{
break;
}
}
if (j >= i)//若一个试除数都无法整除该数,则说明该数为素数
{
printf("%d ", i);
count2++;
}
}
printf("\n循环的次数为:%d", count1);
printf("\n素数的个数为:%d",count2);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
境界2(排除2的倍数的合数)🍖
该方法还是和境界1一样是通过循环遍历所有情况达到目的地,其本质并没有发生任何变化,仅仅是稍微优化了一下下,几乎可以说是可有可无,所以该程序执行效率仍然差。
#include<stdio.h>
int main()
{
int i = 0;
int count1 = 0;//循环的次数
int count2 = 0;//素数的个数
printf("1——120之间素数为:\n");
printf("%d ", 2);//不能忘记2也是素数
count2++;
for (i = 3; i <= 120; i+=2)//省略掉2的倍数的合数
{
int j = 0;
for (j = 2; j < i; j++)//试除除了1和它本身之外所有的数
{
count1++;
if (i % j == 0)
{
break;
}
}
if (j >= i)//若一个试除数都无法整除该数,则说明该数为素数
{
printf("%d ", i);
count2++;
}
}
printf("\n循环的次数为:%d", count1);
printf("\n素数的个数为:%d",count2);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
境界3(试除从 2—sprt(n) )🍖
该方法是通过试除从 2—sprt(n) 之间的所有数来判断是否为素数的,那为什么是 2—sprt(n) 这个范围呢?因为若这个数它不是素数必然可以进行因式分解,分解成两个因数相乘;既然这两个因数都可以用来判断是否为素数,那我们为什么要判断它两遍呢,一遍不就足够了?那该如何实现呢?
如果你多因式分解几组自然数,你会发现分解出来的两个因数必然是一大一小且都相互趋近于被分解的那个数n的算数平方根。所以我们发现第1个因数的范围必然是在 2——sprt(n) 之间,而又由于我们只需要知道其中的一个因数就可以判断是否为素数,故试除的范围就可以定在 2——sprt(n) 之间了,这样我们就可以省略 sprt(n)——(n-1) 之间的试除,这真的是大大优化了境界1时的代码呀!!!
#include<stdio.h>
#include<math.h>
int main()
{
int i = 0;
int count1 = 0;//循环的次数
int count2 = 0;//素数的个数
printf("1——120之间素数为:\n");
for (i = 2; i <= 120; i++)
{
int j = 0;
for (j = 2; j <= sqrt(i); j++)//试除除了2——sqrt(i)之间的数
{
count1++;
if (i % j == 0)
{
break;
}
}
if (j > sqrt(i))//若一个试除数都无法整除该数,则说明该数为素数
{
printf("%d ", i);
count2++;
}
}
printf("\n循环的次数为:%d", count1);
printf("\n素数的个数为:%d", count2);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
筛选法🍖
筛选法的由来可以追溯到古希腊时期,那时有个人叫埃拉托斯特尼,他发现可以通过在涂蜡的木板记下数字,接着在蜡上以记一个点来作为删去一个数字,然后从最小的质数开始一个接着一个的划掉这些质数的倍数的方法来实现求质数(最后那些没被点标记的数就是质数了)。质数查找完成后,这有着密密麻麻小点的涂蜡板看上去就像一个筛子,所以就把着这种方法叫做:“埃拉托斯特尼筛选”,简称:筛选法。
从上面我们可以看出筛选法和试除法其实有着本质上的区别,试除法是判断每一个数是不是素数来达到目的;而筛选法不是如此,筛选法是将不是素数的数全部去除,然后得到余下的数来达到目的。那该如何实现这个代码呢?看下去。
境界1(基础)🍖
首先1不是质数也不是合数,所以要划去;接着2是公认最小的质数,所以要保留下来,再把所有2的倍数去掉;然后接下来遇到的第一数不会是2的倍数,所以它必然只可能被1和他自身整除,为素数,而2后面第一个没有被划去的数是3,所以要保留素数3,再把所有3的倍数去掉;接着往复之前的判断,剩下的那些大于3的数里面,最小的是5,所以5也是质数……
上述过程不断重复,就可以把某个范围内的合数全都除去(就像被筛子筛掉一样),剩下的就是质数了。如果理解还不怎么清晰,我这有幅动图其能够直观地体现出筛法的工作过程,如下所示:
#include<stdio.h>
#include<stdbool.h>
#define NUM 200
int main()
{
//建立一个bool类型的数组,用来存放该数组下标所对应的数是否为素数;是素数则存储true,否则存储false。
bool is_prime[NUM] = { 0 };
int i = 0;
int count1 = 0;//循环总次数
int count2 = 0;//素数的个数
//初始化bool数组
for (i = 0; i < NUM; i++)
{
is_prime[i] = true;
}
printf("1——120之间素数为:\n");
//排查掉不是素数的数,并输出素数
for (i = 2; i <= 120; i++)
{
if (is_prime[i])
{
int j = 0;
count2++;
printf("%d ", i);
for (j = i + i; j <= 120; j += i)//从i+i开始筛i的倍数
{
is_prime[j] = false;
count1++;
}
}
}
printf("\n循环总次数:%d", count1);
printf("\n素数的个数:%d", count2);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
境界2(优化)🍖
其实上面这个程序还可以优化一下,不知道你有没有发现有一些数字我们会重复筛查好多次。就譬如数字6,我在筛查2的倍数时已经把它筛了一次,可在筛查3的倍数时仍然会重复筛,但其实筛一次就够了。所以只要我们能实现每个数只筛一次,就能节约一定的时间,这样程序就可以得到优化。
那该如何做呢?我们发现,当 i=2 时,我们只需从 2 * 2 = 4 开始筛2的倍数;当 i=3 时,其实我们只需从3 * 3 = 9开始筛3的倍数(优化前的代码是从3+3开始筛的,因为前面我已经把2的倍数都筛了一遍,3+3自然也被筛了,所以没有必要再筛一次,那就往后看嘛从 3+3+3 开始筛);当 i=5时 ,我们发现只有当 5+5+5+5+5 的时候(即:5 * 5 = 25)才没有被之前的数筛过,所以从这开始筛5的倍数。总结一下,在筛一个数的倍数时,只要在该数的二次方那里开始筛它的倍数即可实现每个数只筛一次。
#include<stdio.h>
#include<stdbool.h>
#define NUM 200
int main()
{
//建立一个bool类型的数组,用来存放该数组下标所对应的数是否为素数;是素数则存储true,否则存储false。
bool is_prime[NUM] = { 0 };
int i = 0;
int count1 = 0;//循环总次数
int count2 = 0;//素数的个数
//初始化bool数组
for (i = 0; i < NUM; i++)
{
is_prime[i] = true;
}
printf("1——120之间素数为:\n");
//排查掉不是素数的数,并输出素数
for (i = 2; i <= 120; i++)
{
if (is_prime[i])
{
int j = 0;
count2++;
printf("%d ", i);
for (j = i * i; j <= 120; j += i)//从i*i开始筛i的倍数
{
is_prime[j] = false;
count1++;
}
}
}
printf("\n循环总次数:%d", count1);
printf("\n素数的个数:%d", count2);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
总结🍖
你别看试除法的境界3的循环次数和筛选法的循环次数也就差一半,就认为筛选法的效率也就比试除法快一倍。若我们把求素数的范围提到1000以内,筛选法的循环次数为:1411,而试除法的执行次数却是:5228。所以从这可以看出,求素数的范围越大就越能体现试除法的优越性。上面这些就是我今天想向大家分享的素数求解的N种境界!
这份博客👍如果对你有帮助,给博主一个免费的点赞以示鼓励欢迎各位🔎点赞👍评论收藏⭐️,谢谢!!!
如果有什么疑问或不同的见解,欢迎评论区留言欧👀。
int main()
{
int i = 0;
int j = 0;
int count = 0;
for (i = 100; i <= 200; ++i)
{
for (…
int main()
{
int i = 0;
int count = 0;
for (i = 1; i <= 100; i++)
{
//试除法
int j = 0;
for (j = 2; j <= i; j++)
{
if (i%j == 0)
四种境界
1,试除法
2,i=a*b,a或b至少有一个数字<=sqrt(i)
3,偶数中找素数
4,除了2以外,所有可能的质因数都是奇数,所以,就先尝试2,然后从3开始,直到x/2的所有奇数。
前言
素数的定义:
1,质数又称素数,有无限个。一个大于1的自然数,除了1和它本身外,不能被其他自然数(质数)整除,否则称为合数。根据算术基本定理,每一个比1大的整数。
2,要么本身是一个质数,要么可以写成一系列质数的乘积;而且如果不考虑这些质数在乘积中的顺序,那么写出来的形式是唯一…
一、质数和合数
质数:
质数又称**素数**。指在一个大于 1的自然数中,除了 1和此整数自身外,不能被其他自然数整除的数。换句话说,只有两个正因数(1和自己)的自然数即为质数。
最小的素数是 2, 它也是唯一的偶素数。
从小到大的素数依次排列为∶ 2,3,5,7,11,13,17……
合数:
比 1大但不是素数的数称为合数(0 和1 既非素数也非合数)
最小的合数是 4。
从小到大的合数依次排列为∶4,6,8,9,10,12,14……
特别注意:
判断质.
第一种境界:
#include<stdio.h>
int main() {//第一种方法
需求1:/请实现一个函数,对于给定的整型参数 N,该函数能够把自然数中,小于 N 的质数,从小到大打印出来。
比如,当 N = 10,则打印出
2 3 5 7/
"◇境界1
在…
1、具体过程
对于1000000内的数字而言,利用筛选法计算其中素数,并标记出每个素数对应的位置信息。利用prime数组保存范围内的素数;利用position数组保存每个数所…
众所周知,不管是在学习、考试还是以后找工作中,对于求解素数的问题随处可见,而且还是一个重难点,为何要说是重难点呢?主要是因为对于不同的人往往会有不同做法,但大多数掌握的都是一些非常平庸的做法,完全没有技术含量。然而这对于我们这些技术人员无疑是一个BIG BUG。所以小编在此整理了一些求解套路,如有疑问,欢迎来扰。
★试除法:
首先要介绍的,当然非"试除法"莫属啦。考…
def prime(x):
if x == 1:
return False #输入的数是1 返回值是错误
n = int(math.sqrt(x)) #最短区间
for i in range(2,n):
if x % i ==0: # 余数是0就是有能被整除的数
return False
return
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
热门文章
最新评论
您愿意向朋友推荐“博客详情页”吗?
-
强烈不推荐
-
不推荐
-
一般般
-
推荐
-
强烈推荐
晞悦: 真的收获满满
Sherry_greenhand: 而且对于非char类数组,sizeof是每一单位所占字节数乘以长度;strlen似乎是不能求字符数组以外的其他类型数组长度 吧
lai1743341342: 在二、结构体的声明定义初始化 那边的蓝色注意1.的main函数打成mian了把哈哈
m0_70959371: ❗是什么啊
孙吧代码人: 为什么主函数不需要定义字符ABC