第七周7.1数组运算课堂学习记录 求素数的方法改进/优化集锦《程序设计入门——C语言》第七期 浙江大学 翁恺

2023-10-26

求素数基本方法及优化:

1.基本方法求素数:

从2到x-1测试是否可以整除,对于n来说要走n-1遍,n很大时相当于 遍。

#include<iostream>
using namespace std;

/*求素数基本方法*/
//从2到x-1测试是否可以整除,可以则非素数
//对于n来说要走n-1遍,n很大时相当于n遍
int isPrime(int x)	
{
	int ret = 1;
	int i;
	if (x == 1||x==0) { ret = 0; }
	for (i = 2; i < x ; i++)
	{
		if (x%i == 0) {
			ret = 0;
			break;
		}
	}
	return ret;
}

int main(){

	int x;
	scanf("%d", &x);
	if (isPrime(x)) {
		printf("%d是素数\n", x);
	}
	else {
		printf("%d不是素数\n", x);
	}

	system("pause");
	return 0;
}

2.改进isPrime函数求素数:

去掉偶数(偶数一定不是素数)后,从3到x-1,每次加2。

如果x为偶数则立刻能判断,否则循环(n-3)/2遍,当n很大时相当于 n/2 遍。

完整程序(main函数未修改,只修改isPrime函数):

#include<iostream>
using namespace std;

/*求素数改进方法1:
去掉偶数(偶数一定不是素数)后,从3到x-1,每次加2。
如果x为偶数则立刻能判断
否则循环(n-3)/2遍
当n很大时相当于 n/2 遍*/
int isPrime(int x)		
{
	int ret = 1;
	int i;
	if (x == 1 || x == 0 || (x % 2 == 0 && x != 2)) {
		ret = 0; 
	}
	for (i = 3; i < x ; i+=2)
	{
		if (x%i == 0) {
			ret = 0;
			break;
		}
	}
	return ret;
}

int main(){
	int x;
	scanf("%d", &x);
	if (isPrime(x)) {
		printf("%d是素数\n", x);
	}
	else {
		printf("%d不是素数\n", x);
	}
	system("pause");
	return 0;
}

3.进一步改进isPrime函数求素数:

去除偶数后从3遍历到√x即可。只需要循环约 √x/2 (sqrt(x)/2)

数学原理:从素数的定义来看,“一个大于1的自然数,如果除了1和它自身外,不能被其他自然数整除的数。”

          “因数”,我们要寻找的是除了自身与1没有因数的数字。而除了自身的平方根,因数都是成对存在的。而且这些因数对,一定是一大一小(除平方根外)。那么我们只要保留上面的遍历,但将遍历的终点设为所有因数对中较小值中的最大值(即平方根)就可以了。只要这个可以整除的值不存在,就说明该数字不存在因数对。那么自然也就是素数了。故而遍历只用到√x即可。

(注:原理转载自http://blog.sina.com.cn/s/blog_17b3f7fb60102x9wr.html

#include<iostream>
#include<math.h>
using namespace std;

/*求素数改进方法2
去除偶数后从3遍历到√x即可
只需要循环 √x (sqrt(x)) 遍
*/
int isPrime(int x)		
{
	int ret = 1;
	int i;
	if (x == 1 || x == 0 || (x % 2 == 0 && x != 2)) {
		ret = 0; 
	}
	for (i = 3; i <= sqrt(x) ; i+=2)
	{
		if (x%i == 0) {
			ret = 0;
			break;
		}
	}
	return ret;
}

int main(){
	int x;
	scanf("%d", &x);
	if (isPrime(x)) {
		printf("%d是素数\n", x);
	}
	else {
		printf("%d不是素数\n", x);
	}
	system("pause");
	return 0;
}

4.求素数改进方法3:

判断是否能被已知的且<x的素数整除
只需要循环 比√x/2 更少的遍数——即 比x小的素数的个数

#include<iostream>
using namespace std;

/*求素数改进方法3
判断是否能被已知的且<x的素数整除
只需要循环 比√x/2 更少的遍数
*/

//输入已知素数表和要判断的数x,判断x是否能被已知的且<x的素数整除
int isPrime(int x , int knownPrimes[] , int number0fKnowPrimes)		
{
	int ret = 1;
	int i;
	for (i = 0 ; i < number0fKnowPrimes; i++)
	{
		if (x % knownPrimes[i] == 0) {
			ret = 0;
			break;
		}
	}
	return ret;
}

int main(){
	const int number = 7;	//输出前7个素数,可通过更改number改变想输出素数个数
	int prime[number] = { 2 };		//素数数组中第一个素数为2
	int count = 1;		//素数数组中素数的个数
	int i = 3;		//从3开始判断是否为素数

	/*调试用,输出表头
	{
		int i;
		printf("\t\t");
		for (i = 0; i < number; i++) {
			printf("%d\t", i);
		}
		printf("\n");
	}*/

	while (count < number) {
		//如果判断出i是素数的话,就把i加到prime数组中去
		if (isPrime(i, prime, count)) {					
			prime[count++] = i;		//此语句相当于:prime[count] = i;	count++;
		}
		/*调试用,方便输出查看变量变化
		{
			printf("i=%d \tcnt=%d\t", i, count);
			int i;
			for (i = 0; i < number; i++) {
				printf("%d\t", prime[i]);
			}
			printf("\n");
		}*/

		i++;
	}

	for (i = 0; i < number; i++) {
		printf("%d", prime[i]);
		if ((i + 1) % 10) printf("\t");
		else printf("\n");
	}

	system("pause");
	return 0;
}

加上调试查看素数prime数组(前7个)的结果:

不加调试输出前100个素数运行结果:

5.求素数改进方法终极版:构造素数表(和前面的方法思路相反)

构造m以内的素数表步骤:

(1)令x为2

(2)将2x,3x,4x……直至nx<m的标记为非素数(将素数的整数倍数字都标记为非素数)

(3)令x为下一个没有被标记为非素数的数字,重复步骤(2),直到所有的数字都已经尝试完毕,素数表即构造完成。

比如:现在有15以内的数字表:

2 3 4 5 6 7 8 9 10 11 12 13 14 15 

一开始全部标记为素数(红色),x = 2为素数,接着把2所有的倍数标记为非素数(黑色)之后变成:

2 3 4 5 6 7 8 9 10 11 12 13 14 15 

然后令让x为下一个素数,即 x = 3 ,继续把3所有的倍数标记为非素数之后变成:

2 3 4 5 6 7 8 9 10 11 12 13 14 15 

接着令让x为下一个素数,即 x = 5 ,继续把5所有的倍数标记为非素数之后变成:

2 3 4 5 6 7 8 9 10 11 12 13 14 15 

接着令让x为下一个素数,即 x = 7 ……,直到 x = 13 之后,不再有素数,就停止了,最后得到的红色的就是素数,得到了15以内相应的素数表:

2 3  5  7 11 13

伪代码:

代码:

#include<iostream>
using namespace std;

/* 求素数改进方法——构造素数表
将素数的整数倍数字都标记为非素数
遍历剩余素数指导全部标记完为止 */
int main(){
	const int maxNumber = 25;		//打印25以内的素数
	int isPrime[maxNumber];
	int i;
	int x;
	//初始化isPrime数组素数标志均为1
	for (i = 2; i < maxNumber; i++) {
		isPrime[i] = 1;
	}
	for (x = 2; x < maxNumber; x++) {
		//将素数的整数倍数字都标记为非素数
		if (isPrime[x]) {
			for (i = 2; i*x < maxNumber; i++) {
				isPrime[i*x] = 0;
			}
		}
	}

	//打印最终没有被标记为非素数的素数们
	for (i = 2; i < maxNumber; i++) {
		if (isPrime[i]) {
			printf("%d\t", i);
		}
	}
	printf("\n");
	system("pause");
	return 0;
}

输出结果:

测试查看算法标记非素数过程

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

第七周7.1数组运算课堂学习记录 求素数的方法改进/优化集锦《程序设计入门——C语言》第七期 浙江大学 翁恺 的相关文章

  • do{}while(0)的用法

    这几天在看代码的时候遇到了一个好像很神奇的用法 do while 0 do while 1 我能理解 就是一直循环 然后在循环体内设置跳出条件 或者干脆就不跳出 那do while 0 是干嘛的呢 在内部也改变不了循环条件 然后执行一次就结
  • C#8.0本质论第四章--操作符和控制流程

    C 8 0本质论第四章 操作符和控制流程 4 1操作符 有些操作符以符号的形式出现 例如 或者 等 而另一些操作符则为关键词 例如default和is 4 1 1一元正负操作符 一元正操作符 对值几乎没有影响 它在C 中是多余的 4 1 2
  • C++:职工管理系统

    职工管理系统 cpp include
  • c++ 文件类型判断

    要判断文件类型 即判断文件名是否包含文件的后缀 例如 txt文件的判断 string str abcd txt string str1 txt 当 str find str1 string npos时则说明字符串str中不存在 txt 这个
  • C++继承和多态

    C 继承和多态 继承 继承的本质 代码的复用 在基类中给所有派生类提供统一的虚函数接口 让派生类进行重写 然后就可以使用多态了 类和类的关系 a part of 一部分关系 继承 a kind of 一种的关系 继承引入了一些概念 基类 父
  • 输出指令——Console.WriteLine()

    在Console WriteLine 指令中 用 0 1 来表示需替换的变量位置 例子如下 static void Main string args int myInteger string myString myInteger 17 my
  • 解决VS2022版出现“‘cl‘ 不是内部或外部命令”的问题

    在命令行中运行Visual Studio 2022编译器的命令为 cl 但在执行的时候 有可能产生错误 cl 不是内部或外部命令 也不是可运行的程序 或批处理文件 错误原因是系统的环境变量配置有问题 需要手动修改系统环境变量 这里使用两种方
  • 【C++习题笔记】谭浩强C++程序设计(第三版)第五章

    1 用筛法求100之内的素数 筛法又称为筛选法 具体做法是 先把N个自然数按次序排列起来 1不是质数 也不是合数 要划去 第二个数2是质数留下来 而把2后面所有能被2整除的数都划去 2后面第一个没划去的数是3 把3留下 再把3后面所有能被3
  • 苏小红版 c语言程序设计(第三版)系列实验题:学生成绩管理系统V2.0

    github https github com Jackie0Feng SAMS 系统需求描述 某班有最多不超过30人 具体人数由键盘输入 参加某门课的考试 用一维数组和函数指针作为函数参数编程实现如下学生成绩管理 1 录入每个学生的学号和
  • 苏小红版 c语言程序设计(第三版)系列实验题:学生成绩管理系统V5.0

    github https github com Jackie0Feng SAMS 系统需求描述 某班有最多不超过30人 具体人数由键盘输入 参加期末考试 考试科目最多不超过6门 具体门数由键盘输入 定义结构体类型 用结构体数组作函数参数编程
  • C++对象调用优化

    C 对象调用优化 临时对象拷贝构造新对象 临时对象就不会产生 常见的对象调用过程 c 编译器对于对象构造的优化 用临时对象拷贝新对象的时候 临时对象就不产生了 直接构造新对象就可以了 include
  • C++类的三大特性之继承

    目录 一 继承的概念与使用 lt 1 gt 什么是继承 lt 2 gt 如何使用 二 基类与派生类间的转换 三 继承的作用域 四 派生类的默认成员函数 lt 1 gt 构造函数 lt 2 gt 拷贝构造 lt 3 gt 赋值运算符重载 lt
  • 模板特化

    上一篇 模板与重载 里 我遇见了想同时使用模板函数与非模板函数的情况 后来才知道 其实并不需要 当我想对某些特定的类型进行特殊操作时 只需要使用模板特化就可以 所谓特化 就是说对于模板函数 对于某些类型可能需要特殊处理 所以进行特殊化 可以
  • C#学习笔记--关于银行存取款的小实验

    C 面向对象程序设计 编程模拟实现个人银行的存款业务 要求 1 提供两种账户 活期存款账户CheckingCustom和定期存款账户FixedCustom 2 创建活期账户时 必须提供账户名和开户金额 而账号则根据存款分类自动生成 3 不论
  • 【c++primer第五版】第六章函数-函数基础、参数传递、返回类型、函数重载、函数指针

    目录 函数基础 局部对象 函数声明 参数传递 main 处理命令行选项 特殊用途语言特性 调试帮助 函数匹配 函数指针 函数是一个命名了的代码块 通过调用相应的函数来执行相应的代码 函数可以有0或多个参数 通常会产生一个结果 也可以重载函数
  • C++ STL - vector 模拟实现+解析迭代器

    目录 vector使用 vector模拟实现 vector实现解析 memcpy进行元素拷贝问题 扩容问题 vector迭代器解析 vector迭代器失效问题 1 示例一 一个典型的迭代器失效bug insert实现 2 示例二 inser
  • C/C++中的数据结构对齐,#pragma pack() 和 __attribute__

    C C 中的数据结构对齐 总览 数据结构对齐是指在计算机内存中排列和访问数据的方式 它包含三个独立但相关的问题 数据对齐 data alignment 数据结构填充 data structure padding 和打包 packing 当数
  • C++类的构造函数

    构造函数 构造函数的概念 我们有一个Date类 class Date public void Init int year int month int day year year month month day day void Print
  • 第七周7.2搜索 课堂学习记录 搜索例子+选择排序+二分搜索《程序设计入门——C语言》第七期 浙江大学 翁恺

    1 搜索例子 include
  • C#8.0本质论第十六章--使用查询表达式的LINQ

    C 8 0本质论第十六章 使用查询表达式的LINQ 像SQL这样的专业查询语言虽然容易阅读和理解 但又缺乏C 语言的完整功能 这正是C 语言设计者在C 3 0中添加 查询表达式 语法的原因 本章大部分都类似于SQL 一般不会使用到 在用到的

随机推荐