算法-如何求解质数

算法-如何求解质数

1、判断某个数是否为质数

  • 质数的定义
  • 所有的偶数都不是质数
  • 数学定理
  • 已存在的质数表

 

1.1、质数的定义

定理

  总所周知,质数(又称素数)是指在大于 1 的自然数中,除了 1 和它本身以外不再有其他因数的自然数,例如, 7 = 1 * 7,7只有 1和7这两个因素,所以 7 是一个质数;而 8 = 1 * 8 = 2 * 4,它的因数有 1、2、4、8,总共有4个,所以 8 不是质数。我们的代码逻辑可以以质数的定义作为切入点。
  假设要判断的数字是 x,从 2 开始,一般判断到 x - 1 为止,如果中途没有任何一个数被 x 整除,那么就可以判断 x 是一个质数,反之,x 肯定不是质数。
 
C

/** PrimeNumber.c -- 判断某个数是否为素数		*/

#include <stdio.h> 	 /* 标准输入输出函数库		*/
#include <string.h>	 /* 字符串函数库			*/

/******************* 主函数 *******************/
int main(void) 
{
	// 定义一个 int 变量 x 用于接收要判断的数
	int x;
    // 提示性输出
	puts("请输入一个数:");
    
    // 1.读取要判断的整型数字 x 
	scanf("%d", &x);
	// 定义 isPrime 保存判断的结果
	int isPrime = 1, count = 0, i;
    
	// 2.从 2 到 x - 1 循环进行判断
	for(i = 2; i < x; i++) {
        // 计数器 + 1
        count++;
        // 如果 x 能被整除,说明不是其质数,直接跳出循环即可
		if(x%i == 0) {
			isPrime = 0;
			break;
		}
	}
    // 打印循环次数
    printf("总共循环了%d次\n", count);
    
	// 3.输出循环的判断结果
	if(isPrime) {
		printf("%d是一个素数\n", x);
	} else {
		printf("%d不是一个素数\n", x);
	} 
    
	return 0;
}

C语言-第1种方法的输出

Java

import java.util.Scanner;

/**
 * 判断某个数是否为素数
 *
 * @author wl
 */
public class PrimeNumber {

    public static void main(String[] args) {
     	// 创建一个输入扫描仪用于从标准系统输入(控制台)中读取数据
        Scanner in = new Scanner(System.in);
        // 提示性输出   
        System.out.println("请输入一个数:");
        
        // 1.定义 x 并使用从标准系统输入中读取的数据进行初始化
        int x = in.nextInt();
        int count = 0;
        // 定义布尔变量isPrime,保存判断的结果
        boolean isPrime = true;
        
        // 2.循环从 2 到 x - 1 进行判断
        for(int i = 2; i < x; i++) {
            // 计数器 + 1
            count ++;
            // 如果 x 能被整除,说明不是质数,直接跳出循环即可
            if(x%i == 0) {
                isPrime = false;
                break;
            }
        }
        // 打印循环次数
        System.out.println("方法总共循环了" + count + "次");
        
        // 3.输出循环的判断结果
        if(isPrime) {
            System.out.println(x + "是一个素数");
        } else {
            System.out.println(x + "不是一个素数");
        }
    }
}

 
Java语言-第1种方法的输出

 
  OK!让我们来分析一下上面这段代码的时间复杂度,假设 x 是一个不是质数,循环 2 开始,最多要走 x - 1 次 ;如果 x 是一个素数,那么循环最少要走 x - 1 次,最终我们可以得出这段代码的时间复杂度约为 O ( n ) O(n) O(n),可能你会想着这段代码还不错,但是别太高兴,如果 x 是一个非常大的数字呢,循环执行的次数就会很多,假设 x 的值是一百万,一千万,一千万亿呢? 那么循环就可能要运行近百万次,近千万次,近千万亿次,效率会非常非常差,那么有没有什么更好的方法?答案是有的

 

1.2、所有的偶数都不是质数

前言

  从质数的定义,我们不难发现,除了奇数之外,所有的偶数都不可能是质数(除了 2)。比如 4、6、 8、9、10,这些一看都不是质数。因为偶数都是 2 的倍数,能够被 2 整除,所以偶数最少都拥有三个因数(除了 2 )。那么我们可以借此来改进我们的代码,如果 x 是偶数,那么肯定不是质数,循环可以从 3 开始,每次 +2,最少只要循环 ( x − 3 ) 2    +    1 \frac {(x - 3)} { 2 }\;+\;1 2(x3)+1 遍,当 x 很大的时候就是 x 2 \frac {x} {2} 2x 次。
 
C

/** PrimeNumber.c -- 判断某个数是否为素数		*/

#include <stdio.h> 	 /* 标准输入输出函数库		*/
#include <string.h>	 /* 字符串函数库			*/
#include <stdbool.h> /* 布尔类型变量及函数库	*/

/****************** 函数声明 ******************/
/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime01(int x);
/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
*/
bool isPrime02(int x);

/******************* 主函数 *******************/
int main(void) 
{
	// 定义一个 int 变量 x 用于接收要判断的数
	int x;
    // 提示性输出
	puts("请输入一个数:");
    
	// 1.读取要判断的整型数字 x 
    scanf("%d", &x);
	
    // 2.判断并输出结果
    if((isPrime01(x), isPrime02(x))) {
    	printf("%d是一个素数\n", x);
    } else {
    	printf("%d不是一个素数\n", x);
    }
	
    return 0;
}

/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime01(int x)
{
    // 定义 count 变量记录循环次数
	int count = 0;
    // 定义布尔变量isPrime,保存判断的结果
	bool isPrime = true;
	// 从 2 到 x - 1 循环进行判断
	int i;
	for(i = 2; i < x; i++) {
		 count++;
        // 如果 x 能被整除,说明不是质数,直接跳出循环即可
		if(x%i == 0) {
			isPrime = false;
			break;
		}
	}
    // 打印循环次数
    printf("函数1总共循环了%d次\n", count);
    return isPrime;
}

/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime02(int x)
{
    // 定义 count 变量记录循环次数
	int count = 0;
	// 定义布尔变量isPrime,保存判断的结果
	bool isPrime = true;
	/*
		当x等于1时或可以被2整除且不等于2时
		说明其不是质数 
	*/
	if(x == 1 || (x%2 == 0 && x != 2)) {
		isPrime = false;
	}
    // 循环从 2 到 x - 1 进行判断
    int i;
    for(i = 3; i < x; i += 2) {
        // 计数器 + 1
        count++;
        if(x%i == 0) {
            isPrime = false;
            break;
        }
    }  
    // 打印循环次数
	printf("函数2总共循环了%d次\n", count);
    return isPrime;
}

C语言-第2种方法的输出

Java

/**
 * 判断某个数是否为素数
 *
 * @author wl
 */
public class PrimeNumber {

    public static void main(String[] args) {
        // 创建一个输入扫描仪用于从标准系统输入(控制台)中读取数据
        Scanner in = new Scanner(System.in);
        // 提示性输出
        System.out.println("请输入一个数:");
        
        // 1.定义 x 并使用从标准系统输入中读取的数据进行初始化
        int x = in.nextInt();
        
       	// 2.判断并输出结果
        if(PrimeNumber.primeJudge01(x) && PrimeNumber.primeJudge02(x)) {
            System.out.println(x + "是一个素数");
        } else {
            System.out.println(x + "不是一个素数");
        }
    }
    
    /**
     * 第一个方法
     * 质数只能被1和自身整除
     *
     * @param x 要判断的数字
     * @author wl
     * @date 2022/8/2 22:55
     * @return 判断的结果
     */
    public static boolean primeJudge01(int x) {
        // 定义 count 变量记录循环次数
        int count = 0;
        // 定义 布尔变量isPrime
        boolean isPrime = true;
        // 循环从 2 到 x - 1 进行判断
        for(int i = 2; i < x; i++) {
            count++;
            if(x%i == 0) {
                isPrime = false;
                break;
            }
        }
        System.out.println("方法1总共循环了" + count + "次");
        return isPrime;
    }

    /**
     * 第二个方法
     * 所有的偶数都不是质数
     *
     * @param x 要判断的数字
     * @author wl
     * @date 2022/8/2 22:55
     * @return 判断的结果
     */
    public static boolean primeJudge02(int x) {
        // 定义 count 变量记录循环次数
        int count = 0;
        // 定义 布尔变量isPrime
        boolean isPrime = true;
        if(x == 1 || (x%2 == 0 && x != 2)) {
            // 当 x 为 1 时或可以被2整除且不是2时不是质数 
            isPrime = false;
        }
        // 循环从 2 到 x - 1 进行判断
        for(int i = 3; i < x; i += 2) {
            count++;
            if(x%i == 0) {
                isPrime = false;
                break;
            }
        }
        System.out.println("方法2总共循环了" + count + "次");
        return isPrime;
    }
}

在这里插入图片描述

  通过实际的对比,我们可以很明显地看出,第二种方法,比第一种方法快了一半,时间复杂度约为 O ( n 2 ) O(\frac {n} {2}) O(2n),这足以说明这个方法比前一种方法高明多了,但是我相信在座的各位同学,肯定不会止步于此,是的,确实还有更快的方法。
 

1.3、数学定理

我们先做一个假设,如果 a * b = 81 ,那么 81 的平方根会以 9 为中心,a 和 b 中一定有一个是小于等于 9 的,而另外一个是大于等于 9 的。

  • 假设都是大于 9 —— 9.1 ∗ 9.1 > 81 9.1 * 9.1 > 81 9.19.1>81

  • 假设都是小于 9 —— 8.9 ∗ 8.9 < 81 8.9 * 8.9 < 81 8.98.9<81

由此,我们可以得出一个结论:一个数的因数一定小于或等于这个数的平方根
 
C

/** PrimeNumber.c -- 判断某个数是否为素数		*/

#include <stdio.h> 	 /* 标准输入输出函数库		*/
#include <string.h>	 /* 字符串函数库			*/
#include <stdbool.h> /* 布尔类型变量及函数库	*/
#include <math.h>	 /* 数学函数库				*/

/****************** 函数声明 ******************/

/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime01(int x);

/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime02(int x);
    
/*
	判断某个数是否为质数

	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime03(int x);

/******************* 主函数 *******************/
int main(void) 
{
	// 定义一个变量用于接受要判断的数
	int x;
    // 提示性输出
	puts("请输入一个数:");
    
    // 1.读取要判断的整型数字 x 
	scanf("%d", &x);

	// 2.判断并输出结果
	if((isPrime01(x), isPrime02(x), isPrime03(x))) {
		printf("%d是一个素数\n",x);
	} else {
		printf("%d不是一个素数\n",x);
	}

	return 0;
}

/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime01(int x)
{
    // 定义 count 变量记录循环次数
	int count = 0;
    // 定义布尔变量isPrime,保存判断的结果
	bool isPrime = true;
	// 从 2 到 x - 1 循环进行判断
	int i;
	for(i = 2; i < x; i++) {
		 count++;
        // 如果 x 能被整除,说明不是质数,直接跳出循环即可
		if(x%i == 0) {
			isPrime = false;
			break;
		}
	}
    // 打印循环次数
    printf("函数1总共循环了%d次\n", count);
    return isPrime;
}

/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime02(int x)
{
    // 定义 count 变量记录循环次数
	int count = 0;
	// 定义布尔变量isPrime,保存判断的结果
	bool isPrime = true;
	/*
		当x等于1时或可以被2整除且不等于2时
		说明其不是质数 
	*/
	if(x == 1 || (x%2 == 0 && x != 2)) {
		isPrime = false;
	}
    // 循环从 2 到 x - 1 进行判断
    int i;
    for(i = 3; i < x; i += 2) {
        // 计数器 + 1
        count++;
        if(x%i == 0) {
            isPrime = false;
            break;
        }
    }  
    // 打印循环次数
	printf("函数2总共循环了%d次\n", count);
    return isPrime;
}

/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime03(int x)
{
    // 定义 count 变量记录循环次数
	int count = 0;
	// 定义布尔变量isPrime,保存判断的结果
	bool isPrime = true;
	// 循环从 2 到 x - 1 进行判断
	if(x == 1 || (x%2 == 0 && x != 2)) {
		// 当 x 为 1 时不是质数 
		isPrime = false;
	} 
    int i;
    // 利用 math.h 头文件中的平方根函数sqrt()求解质数
    for(i = 3; i < sqrt(x); i += 2) {
        count++;
        if( x % i == 0) {
            isPrime = false;
            break;
        }
    }
	printf("函数3总共循环了%d次\n", count);
    return isPrime;
}

C语言第3种方法的输出

Java

import java.util.Scanner;

/**
 * 判断某个数是否为素数
 *
 * @author wl
 * @date 2022/8/2 22:09
 */
public class PrimeNumber {

    public static void main(String[] args) {
        // 创建一个输入扫描仪用于从标准系统输入(控制台)中读取数据
        Scanner in = new Scanner(System.in);
        // 提示性输出
        System.out.println("请输入一个数:");
        
        // 1.定义 x 并使用从标准系统输入中读取的数据进行初始化
        int x = in.nextInt();
        
       	// 2.判断并输出结果
        if(PrimeNumber.primeJudge01(x) 
           && PrimeNumber.primeJudge02(x) 
           && PrimeNumber.primeJudge03(x)) {
            System.out.println(x + "是一个素数");
        } else {
            System.out.println(x + "不是一个素数");
        }
    }

     /**
     * 第一个方法
     * 质数只能被1和自身整除
     *
     * @param x 要判断的数字
     * @author wl
     * @date 2022/8/2 22:55
     * @return 判断的结果
     */
    public static boolean primeJudge01(int x) {
        // 定义 count 变量记录循环次数
        int count = 0;
        // 定义 布尔变量isPrime
        boolean isPrime = true;
        // 循环从 2 到 x - 1 进行判断
        for(int i = 2; i < x; i++) {
            count++;
            if(x%i == 0) {
                isPrime = false;
                break;
            }
        }
        System.out.println("方法1总共循环了" + count + "次");
        return isPrime;
    }

    /**
     * 第二个方法
     * 所有的偶数都不是质数
     *
     * @param x 要判断的数字
     * @author wl
     * @date 2022/8/2 22:55
     */
    public static boolean primeJudge02(int x) {
        // 定义 count 变量记录循环次数
        int count = 0;
        // 定义 布尔变量isPrime
        boolean isPrime = true;
        if(x == 1 || (x%2 == 0 && x != 2)) {
            // 当 x 为 1 时或可以被2整除且不是2时不是质数 
            isPrime = false;
        }
        // 循环从 2 到 x - 1 进行判断
        for(int i = 3; i < x; i += 2) {
            count++;
            if(x%i == 0) {
                isPrime = false;
                break;
            }
        }
        System.out.println("方法2总共循环了" + count + "次");
        return isPrime;
    }

    /**
     * 第三个方法
     * 如果在 x 的平方根范围内不能被整除,
     * 那么 x 就一定是个质数
     *
     * @param x 要判断的数字
     * @author wl
     * @date 2022/8/2 22:55
     * @return 判断的结果
     */
    public static boolean primeJudge03(int x) {
        // 定义 count 变量记录循环次数
        int count = 0;
        // 定义 布尔变量isPrime
        boolean isPrime = true;
        if(x == 1 || x == 0) {
            isPrime = false;
        } else {
            // 循环从 2 到 Math.sqrt(x) 进行判断
            for(int i = 3; i < Math.sqrt(x); i += 2) {
                count++;
                if(x%i == 0) {
                    isPrime = false;
                    break;
                }
            }
        }
       	System.out.println("方法3总共循环了" + count + "次");
        return isPrime;
    }
}

Java语言第3种方法的输出

  这段代码的时间复杂度约为 O ( n 1 2 ) O(n^{\frac{1}{2}}) O(n21)。可以看出,相同的数,第三个方法只执行了二十多次,简直是比闪电侠还快。不过这个方法也不是最优解,实际上,我们还可以通过已存在的质数,创建一张质数表来判断质数

1.4、已存在的质数表

  现在不需要拿比 x 小的数来测试 x 是不是质数,只要拿出比 x 小的质数来测试它是不是质数。因为质数是相对比较少的数,大部分的数字甚至都不是质数,所以比 x 小的质数是比 sqrt(x) 相对更少,但是,这就有个前提,我们需要有一张已有质数的表,然后根据这张表我们才可以判断,我们的这个 x 是不是质数,所以这个程序就特别适合于:我正在构造这么一张表,然后我在构造表的过程中考虑如何把新的数据项加到这个表里面去。

C

/** PrimeNumber.c -- 判断某个数是否为素数		*/

#include <stdio.h> 	 /* 标准输入输出函数库		*/
#include <stdlib.h>	 /* 标准工具函数库			*/
#include <string.h>	 /* 字符串函数库			*/
#include <stdbool.h> /* 布尔类型变量及函数库	*/
#include <math.h>	 /* 数学函数库				*/
#define N 32677		 /* 定义常量N作为数组的长度	*/


/****************** 函数声明 ******************/

/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime01(int x);

/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime02(int x);
    
/*
	判断某个数是否为质数

	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime03(int x);

/*
	使用已存在的质数表
	判断某个数是否为质数

	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime04(int x);

/*
	构造 N 以内的质数表

	@param knowPrimes 要构造的质数表
*/
void createTable(int knowPrimes[]);

/*  
	判断一个数在数组中是否为质数
	是的话返回 true,反之返回false

	@param x 要判断的数
	@param knownPrimes 质数表
	@return 结果
*/
int isPrimeInArray(int x, int knownPrimes[], int numberOfKnownPrimes);

/******************* 主函数 *******************/
int main(void) 
{
	// 定义一个变量用于接受要判断的数
	int x;
    // 提示性输出
	puts("请输入一个数:");
    
    // 1.读取要判断的整型数字 x 
	scanf("%d", &x);

	// 2.判断并输出结果
	if((isPrime01(x), isPrime02(x), isPrime03(x), isPrime04(x))) {
		printf("%d是一个素数\n",x);
	} else {
		printf("%d不是一个素数\n",x);
	}
	
	return 0;
}

/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime01(int x)
{
    // 定义 count 变量记录循环次数
	int count = 0;
    // 定义布尔变量isPrime,保存判断的结果
	bool isPrime = true;
	// 从 2 到 x - 1 循环进行判断
	int i;
	for(i = 2; i < x; i++) {
		 count++;
        // 如果 x 能被整除,说明不是质数,直接跳出循环即可
		if(x%i == 0) {
			isPrime = false;
			break;
		}
	}
    // 打印循环次数
    printf("函数1总共循环了%d次\n", count);
    return isPrime;
}

/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime02(int x)
{
    // 定义 count 变量记录循环次数
	int count = 0;
	// 定义布尔变量isPrime,保存判断的结果
	bool isPrime = true;
	/*
		当x等于1时或可以被2整除且不等于2时
		说明其不是质数 
	*/
	if(x == 1 || (x%2 == 0 && x != 2)) {
		isPrime = false;
	}
    // 循环从 2 到 x - 1 进行判断
    int i;
    for(i = 3; i < x; i += 2) {
        // 计数器 + 1
        count++;
        if(x%i == 0) {
            isPrime = false;
            break;
        }
    }  
    // 打印循环次数
	printf("函数2总共循环了%d次\n", count);
    return isPrime;
}

/*
	判断某个数是否为质数
	
	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime03(int x)
{
    // 定义 count 变量记录循环次数
	int count = 0;
	// 定义布尔变量isPrime,保存判断的结果
	bool isPrime = true;
	// 循环从 2 到 x - 1 进行判断
	if(x == 1 || (x%2 == 0 && x != 2)) {
		// 当 x 为 1 时不是质数 
		isPrime = false;
	} 
    int i;
    // 利用 math.h 头文件中的平方根函数sqrt()求解质数
    for(i = 3; i < sqrt(x); i += 2) {
        count++;
        if( x % i == 0) {
            isPrime = false;
            break;
        }
    }
	printf("函数3总共循环了%d次\n", count);
    return isPrime;
}

/*
	使用已存在的质数表
	判断某个数是否为质数

	@param x 要判断的数字
	@return 判断结果,如果是质数返回true,反之返回false
 */
bool isPrime04(int x)
{
	int count = 0, i;
	bool isPrime = true;
	if(x == 1 || (x%2 == 0 && x != 2)) {
		isPrime = false;
	} else {
		// 因为 x 的值可能非常大,故而申请堆内存
		int *prime = (int*) malloc(sizeof(int) * N);
		// 创建质数表
		createTable(prime);
		for (i = 0; i < N && prime[i] < sqrt(x); i++)
		{
			count++;
			if(x % prime[i] == 0) {
				isPrime = false;
				break;
			}
		}
		// 释放借来的堆内存,有借有还再借不难
		free(prime);
	}
	printf("函数4总共循环了%d次\n", count);
	return isPrime;
}

/*
	构造 N 以内的质数表

	@param knowPrimes 要构造的质数表
*/
void createTable(int knowPrimes[]) 
{
	knowPrimes[0] = 2;
	int count = 1, i = 3;
	/*{
		printf("\t\t");
		int i;
		for (i = 0; i < N; i++)
		{
			printf("%d\t", i);
		}
		putchar('\n');
	}*/
	while (count < N)
	{
		if (isPrimeInArray(i, knowPrimes, count)) {
			knowPrimes[count++] = i;
		}
		// 调试代码
		/*{
			printf("i=%d \tcnt=%d\t", i, count);
			int i;
			for (i = 0; i < n; i++)
			{
				printf("%d\t", knowPrimes[i]);
			}
			putchar('\n');
		}*/
		i++;
	}

	/*for (i = 0; i < N; i++)
	{
		printf("%d", knowPrimes[i]);
		if ((i+1)%5 != 0) {
			putchar('\t');
		} else {
			putchar('\n');
		}
	}*/

}

/*  
	判断一个数在数组中是否为质数
	是的话返回 true,反之返回false

	@param x 要判断的数
	@param knownPrimes 质数表
	@return 结果
*/
int isPrimeInArray(int x, int knownPrimes[], int numberOfKnownPrimes)
{
	int ret = 1, i;
	for (i = 0; i < numberOfKnownPrimes; i++)
	{
		if (x % knownPrimes[i] == 0) {
			ret = 0;
			break;
		}
	}

	return ret;
}

C语言-第4种方法的输出

Java

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * 判断某个数是否为素数
 *
 * @author wl
 */
public class PrimeNumber {

    /**
     * 质数表的长度
     */
    private final static Integer N = 10;

    /**
     * 质数表
     */
    public final static List<Integer> PRIME_LIST = new ArrayList<>(N);

    static {
        createTable(PRIME_LIST);
    }

    public static void main(String[] args) {
        // 创建一个输入扫描仪用于从标准系统输入(控制台)中读取数据
        Scanner in = new Scanner(System.in);
        // 提示性输出
        System.out.println("请输入一个数:");

        // 1.定义 x 并使用从标准系统输入中读取的数据进行初始化
        int x = in.nextInt();

        // 2.判断并输出结果
        if (PrimeNumber.primeJudge01(x)
                && PrimeNumber.primeJudge02(x)
                && PrimeNumber.primeJudge03(x)
                && PrimeNumber.primeJudge04(x)) {
            System.out.println(x + "是一个素数");
        } else {
            System.out.println(x + "不是一个素数");
        }
    }

    /**
     * 第一个方法
     * 质数只能被1和自身整除
     *
     * @param x 要判断的数字
     * @author wl
     * @date 2022/8/2 22:55
     * @return 判断的结果
     */
    public static boolean primeJudge01(int x) {
        // 定义 count 变量记录循环次数
        int count = 0;
        // 定义 布尔变量isPrime
        boolean isPrime = true;
        // 循环从 2 到 x - 1 进行判断
        for (int i = 2; i < x; i++) {
            count++;
            if (x % i == 0) {
                isPrime = false;
                break;
            }
        }
        System.out.println("方法1总共循环了" + count + "次");
        return isPrime;
    }

    /**
     * 第二个方法
     * 所有的偶数都不是质数
     *
     * @param x 要判断的数字
     * @author wl
     * @date 2022/8/2 22:55
     * @return 判断的结果
     */
    public static boolean primeJudge02(int x) {
        // 定义 count 变量记录循环次数
        int count = 0;
        // 定义 布尔变量isPrime
        boolean isPrime = true;
        if (x == 1 || (x % 2 == 0 && x != 2)) {
            // 当 x 为 1 时或可以被2整除且不是2时不是质数
            isPrime = false;
        }
        // 循环从 2 到 x - 1 进行判断
        for (int i = 3; i < x; i += 2) {
            count++;
            if (x % i == 0) {
                isPrime = false;
                break;
            }
        }
        System.out.println("方法2总共循环了" + count + "次");
        return isPrime;
    }

    /**
     * 第三个方法
     * 如果在 x 的平方根范围内不能被整除,
     * 那么 x 就一定是个质数
     *
     * @param x 要判断的数字
     * @author wl
     * @date 2022/8/2 22:55
     * @return 判断的结果
     */
    public static boolean primeJudge03(int x) {
        // 定义 count 变量记录循环次数
        int count = 0;
        // 定义 布尔变量isPrime
        boolean isPrime = true;
        if (x == 1 || x == 0) {
            isPrime = false;
        } else {
            // 循环从 2 到 Math.sqrt(x) 进行判断
            for (int i = 3; i < Math.sqrt(x); i += 2) {
                count++;
                if (x % i == 0) {
                    isPrime = false;
                    break;
                }
            }
        }
        System.out.println("方法3总共循环了" + count + "次");
        return isPrime;
    }

    /**
     * 第四个方法
     * 使用已存在的质数表
     * 判断某个数是否为质数
     *
     * @param x 要判断的数字
     * @author wl
     * @date 2022/8/2 22:55
     * @return 判断的结果
     */
    public static boolean primeJudge04(int x) {
        int count = 0;
        boolean isPrime = true;
        if (x == 1 || (x % 2 == 0 && x != 2)) {
            isPrime = false;
        } else {
            double sqrt = Math.sqrt(x);
            for (int i = 0; i < N && PRIME_LIST.get(i) < sqrt; i++) {
                count++;
                if (x % PRIME_LIST.get(i) == 0) {
                    isPrime = false;
                    break;
                }
            }
        }
        System.out.println("方法4总共循环了" + count + "次");
        return isPrime;
    }

    /**
     * 构造 N 以内的质数表
     *
     * @param knowPrimes 要构造的质数表
     */
    private static void createTable(List<Integer> knowPrimes) {
        knowPrimes.add(2);
        int count = 1, idx = 3;
        // 调试代码
        /*System.out.print("\t\t\t\t");
        for (int i = 0; i < N; i++) {
            System.out.print(i + "\t");
        }
        System.out.println();*/
        while (count < N) {
            if (isPrimeInArray(idx, knowPrimes, count)) {
                knowPrimes.add(idx);
                count++;
            }
            // 调试代码
            /*System.out.print("idx=" + idx + "\tcnt=" + count + "\t");
            for (Integer knowPrime : knowPrimes) {
                System.out.print(knowPrime + "\t");
            }
            System.out.println();*/
            idx++;
        }

        /*for (int i = 0; i < knowPrimes.size(); i++) {
            System.out.print(knowPrimes.get(i));
            if ((i + 1) % 5 != 0) {
                System.out.print("\t");
            } else {
                System.out.println();
            }
        }*/

    }

    /**
     * 判断一个数在数组中是否为质数
     * 是的话返回 true,反之返回false
     *
     * @param x           要判断的数
     * @param knownPrimes 质数表
     * @return 判断的结果
     */
    private static boolean isPrimeInArray(int x, List<Integer> knownPrimes, int numberOfKnownPrimes) {
        boolean ret = true;
        for (int i = 0; i < numberOfKnownPrimes; i++) {
            if (x % knownPrimes.get(i) == 0) {
                ret = false;
                break;
            }
        }
        return ret;
    }

}

Java语言-第4种方法的输出

 

2、构造一张纯素数表

  前面做了很多判断质数的方法,但是代码的基本思路其实是一样的,都是说输入一个数,然后想办法构造一些东西对它做整除,看看能不能整除,能被整除就不是素数。不同的是用来除它的数越来越少。我们在每一次的判断中尽量使得程序越来越快,循环的次数也越来越少,但是在求解质数的方法上,并不是只有这一种想法,如果用相反的想法来思考这件事情,假设现在我们不是去判断某个数是否为质数,而是构造出这样一张表,当这张表构造完成的时候,表里留下的全部数据都是素数,这样想的话是不是会好很多?

  算法是这样的,如果要构造 n 以内(不含 n)的素数表:

  1. 令 x 为 2
  2. 将 2x、3x、4x 直至 ax <n 的数(即 x 的倍数)标记为非素数
  3. 令 x 为下一个没有被标记为非素数的数,然后重复第二步,直到所有的数都尝试完毕后

 

伪代码

  1. 开辟 prime[n],初始化其所有元素为 1, prime[x] 为1

    表示 x 是素数

  2. x = 2

  3. 如果 x 是素数,则对于 (i =2; x*i < n; i++)prime[i*x] = 0

  4. x++,如果 x < n,重复 3,否则结束

 

代码实现

/** constructPrimerNumberTable.c -- 构造一张纯素数表 */
#include <stdio.h>

/*
	求 maxNumber 以内的素数
*/
int main(void)
{
	// 初始化程序
	const int maxNumber = 5000;
	int prime[maxNumber];
	int i, x;
	// 1.初始化数组
	for (i = 0; i < maxNumber; i++)
	{
		prime[i] = 1;
	}
	// 2.标记数组中不是素数的数据
	for (x = 2; x < maxNumber; x++)
	{
		if (prime[x]) {
			for (i = 2; i*x < maxNumber; i++)
			{
				prime[i*x] = 0;
			}
		}
	}
	// 3.输出未被标记的数据(即素数)
	int count = 0;
	printf("从 1 到 %d 的素数有:\n", maxNumber);
	for (i = 2; i < maxNumber; i++)
	{
		if (prime[i]) {
			printf("%d", i);
			if ((count+1)%5 != 0) {
				putchar('\t');
			} else {
				putchar('\n');
			}
			count++;
		}
	}
	putchar('\n');
	return 0;
}

 

3、总结

  通过上面的练习,我们可以了解到,算法和人的思维方式不一定相同,只有通过不断的练习和发掘其中的关联信息,找到最优解,才能优化或改进代码。事实上,历史上有一些算法就是改进其他算法而得来,比如希尔排序,也被称为最小增量排序,其排序算法就是在直接插入排序的基础上稍加改进而得来的。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值