当前位置: 首页 > news >正文

第三十五天:寻找质数

寻找质数

一、质数的定义与特性

质数(又称素数)是指大于1的自然数中,除了1和其本身外,不能被其他自然数整除的数。具体特性如下:

  1. 基本定义:

    • 必须是大于1的正整数
    • 仅有两个正因数(1和自身)
    • 数量无限(欧几里得已证明)
  2. 主要性质:

    • 最小质数为2,且是唯一的偶质数
    • 质数序列:2,3,5,7,11,13,17,19,23,29…
    • 任何大于1的整数要么是质数,要么可分解为质数的乘积
  3. 应用领域:

    • 密码学:RSA加密算法利用大质数的难以分解特性
    • 计算机科学:哈希表常选用质数大小以降低冲突概率
    • 数学研究:与哥德巴赫猜想、黎曼假设等重大问题相关
  4. 判定方法:

    • 试除法:用不超过√n的质数逐一试除
    • 费马检验:基于费马小定理的概率性检测
    • AKS算法:首个多项式时间确定性检测算法
  5. 特殊类别:

    • 梅森素数:形式为2^p-1的质数
    • 孪生质数:相差2的质数对(如11与13)
    • 安全质数:满足2q+1形式的质数(q同为质数)

二、问题及思路

  • 如果一个正整数只能被 1 和它本身整除,就称为一个质数。最小的几个质数依次是 2,3,5,7,11,13,…2,3,5,7,11,13,….请问,第 2025 个质数是多少?
  • 输出格式输出一个整数,表示第 2025个质数。
  • 要找到第 2025 个质数,最直接的方法就是从最小的质数 2 开始,逐个检查每个整数是否为质数,同时记录找到的质数个数,当找到第 2025 个质数时,输出该数即可。

三、C++ 代码实现

#include <iostream>
#include <cmath>// 判断一个数是否为质数
bool isPrime(int num) {if (num <= 1) return false;if (num == 2) return true;if (num % 2 == 0) return false;for (int i = 3; i <= sqrt(num); i += 2) {if (num % i == 0) return false;}return true;
}int main() {int count = 0; // 记录找到的质数个数int num = 2; // 从最小的质数2开始检查while (true) {if (isPrime(num)) {count++;if (count == 2025) {std::cout << num << std::endl;break;}}num++;}return 0;
}

四、代码解析

  1. isPrime函数:用于判断一个数是否为质数。
    • 首先处理一些特殊情况:如果数字小于等于1,那它肯定不是质数,直接返回false。
    • 如果数字是2,2是质数,返回true。
    • 如果数字是大于2的偶数,由于偶数能被2整除,所以不是质数,返回false。
    • 对于大于2的奇数,从3开始,每次增加2,一直到该数的平方根为止进行检查。这是因为如果一个数不是质数,那么它一定可以分解成两个因数,其中一个因数必定小于等于它的平方根。如果在这个范围内找到了能整除该数的因数,那么这个数就不是质数,返回false;如果遍历完都没有找到,说明这个数是质数,返回true。
  2. main函数
    • 初始化两个变量,count用于记录找到的质数个数,初始值为0;num从最小的质数2开始,作为被检查的数字。
    • while (true)无限循环中,对num调用isPrime函数判断是否为质数。如果是质数,count加1。当count达到2025时,说明找到了第2025个质数,输出该数并使用break跳出循环。每次循环结束后,num自增1,继续检查下一个数。

五、寻找大序号的质数

1、暴力法的局限性

第2025个质数”的暴力思路:从2开始逐个判断是否为质数,直到累计到目标序号。代码逻辑为:

bool isPrime(int n) { /* 暴力判断质数 */ }
int findNthPrime(int n) {int count = 0, num = 2;while (true) {if (isPrime(num)) count++;if (count == n) return num;num++;}
}

问题:当n很大时(如n=100000),每个数的质数判断都要遍历到√num,时间复杂度接近 O(nn)O(n\sqrt{n})O(nn),速度极慢。

2、优化方向:减少重复计算

(1)利用质数分布特性

质数除了2和3,都可表示为6k±1的形式(证明:6的倍数周围,6k、6k+2、6k+3、6k+4都能被2或3整除,只有6k±1可能是质数)。

优化isPrime函数

bool isPrime(int num) {if (num <= 3) return num > 1;if (num % 2 == 0 || num % 3 == 0) return false;for (int i = 5; i * i <= num; i += 6) {if (num % i == 0 || num % (i + 2) == 0) return false;}return true;
}

效果:将质数判断的循环次数减少约1/3(只需检查6k±1形式的数)。

(2) 预存已知质数,加速判断

如果我们维护一个已找到的质数列表,判断新数是否为质数时,只需用列表中小于等于√num的质数试除。

示例代码

#include <vector>
bool isPrime(int num, const std::vector<int>& primes) {for (int p : primes) {if (p * p > num) break; // 超过√num,无需继续if (num % p == 0) return false;}return true;
}int findNthPrime(int n) {std::vector<int> primes = {2, 3}; // 预存小质数if (n <= 2) return primes[n-1];int count = 2, num = 5;while (count < n) {if (isPrime(num, primes)) {primes.push_back(num);count++;}num += 2; // 只检查奇数}return primes.back();
}

原理:因为所有合数都能分解为质数的乘积,所以用已找到的质数试除即可判断新数是否为质数,避免了“从2开始遍历所有数”的冗余。

3、筛法:批量生成质数

当需要找连续区间内的所有质数(从而间接得到大序号质数)时,筛法的效率远超暴力枚举。

(1) 埃拉托斯特尼筛法(Sieve of Eratosthenes)

核心思想:从2开始,把每个质数的倍数标记为合数,剩下的未被标记的就是质数。

示例(找≤N的所有质数)

#include <vector>
std::vector<int> sieve(int n) {std::vector<bool> isPrime(n + 1, true);isPrime[0] = isPrime[1] = false;for (int i = 2; i * i <= n; i++) {if (isPrime[i]) {for (int j = i * i; j <= n; j += i) {isPrime[j] = false;}}}// 收集所有质数std::vector<int> primes;for (int i = 2; i <= n; i++) {if (isPrime[i]) primes.push_back(i);}return primes;
}

局限性:需要预先知道“要找的质数不超过N”,但大序号质数的N难以预估。

(2) 线性筛法(欧拉筛)

优势:保证每个合数仅被其最小质因数标记一次,时间复杂度为 O(n)O(n)O(n),是理论上“筛质数”的最优复杂度。

示例代码

#include <vector>
std::vector<int> linearSieve(int n) {std::vector<bool> isPrime(n + 1, true);std::vector<int> primes;isPrime[0] = isPrime[1] = false;for (int i = 2; i <= n; i++) {if (isPrime[i]) {primes.push_back(i);}for (int p : primes) {if (i * p > n) break;isPrime[i * p] = false;if (i % p == 0) break; // 保证仅被最小质因数筛除}}return primes;
}

适用场景:需要批量生成连续区间内的质数时,线性筛法是首选。

4、大序号质数的工程化思路

若要找极大序号的质数(如第10^6个),需结合“筛法预生成+局部暴力判断”:

  1. 步骤1:用线性筛法预生成前k个质数(k为较大的预估值)。
  2. 步骤2:若预生成的质数数量不足目标序号,从筛法的最后一个数开始,用“预存质数试除”的方法继续找,直到累计到目标序号。

示例逻辑

int findHugeNthPrime(int n) {// 步骤1:线性筛预生成一批质数int estimate = n * log(n) + n * log(log(n)); // 质数定理估算上界std::vector<int> primes = linearSieve(estimate);// 步骤2:若预生成不足,继续暴力找if (primes.size() >= n) return primes[n-1];int count = primes.size();int num = primes.back() + 2; // 从下一个奇数开始while (count < n) {if (isPrime(num, primes)) {primes.push_back(num);count++;}num += 2;}return primes.back();
}
http://www.dtcms.com/a/412610.html

相关文章:

  • 专门做油画交流的网站泰安网站建设工作室
  • 吴恩达d2
  • 学做课件的网站wordpress建站需要学什么意思
  • 营销型网站建设主要教学内容赣州人才网招聘网
  • 网站建设和维护要点wordpress搭建的博客
  • 《道家理论 与现代物理前沿理论对照表》
  • 本网站只做信息展示不提供在线交易wordpress壁纸主题
  • 政务公开及网站建设意见电子商务营销手段有哪些
  • 电感式传感器
  • 山东通信安全员A证考试的难度如何?
  • 网站建设明细费用知名品牌网站有哪些
  • 广东省建设厅的注册中心网站整站优化报价
  • GESP C++5级 2025年6月编程2题解:最大公因数
  • 做搜狗网站优化首页软英文建站平台有哪些
  • 网站项目维护费用宣传片制作合同范本
  • 安宁网站建设 熊掌基于.net平台网站内容管理系统研究与实现
  • 什么是 glTF:完整指南
  • 怎样360网站做推广域名申请网站
  • 营销型网站软件下载网站模板后本地的网站会自动做跳转
  • 建设银行银行号查询网站网页与网站设计
  • 深圳网站建设信科网络建设厅八大员在哪个网站查询
  • 卖护肤在哪个网站做宣传好自动点击器安卓
  • iis v6 新建网站网站如何生成二维码
  • 网站开发中存在的问题常州企业做网站
  • 讯美深圳网站建设厦门seo传播
  • 快速构建高性能 web 应用!了解 Gin Web 框架
  • 官方网站下载打印机的驱动电商网站建设收费
  • 免费的网页模板网站定制女仆
  • 八股(9.26)
  • Linux 基本命令超详细解释第三期 grep | wc | 管道符‘|’ | echo | tail | 重定向符