C语言练习之求质数

C语言练习之求质数

前言

质数又称素数,指整数在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数。换句话说,只有两个正因数(1和自己)的自然数即为质数。比1大但不是质数的数称为合数。0和1既非质数也非合数。

下面介绍基础的与质数相关的C语言练习。

输出质数

题目要求:输出100以内的所有质数

这题最常见的方式是用两层for循环实现。第一层将digit遍历从3到100的所有奇数(2可以直接输出),第二层循环定义一个除数divisor。其中内循环通常有三种方式:divisor < digit; divisor < (digit / 2); 引入math.h库divisor < sqrt(digit)。

第一种
#include <stdio.h>
int main() {
    printf("2\n");
    int digit;
    int divisor;
    for (digit = 3; digit <= 100; digit += 2) 
    {        
        for (divisor = 2; divisor < digit; divisor ++) 
        {                    
			if (digit % divisor == 0)
            break;
        }
		if(divisor == digit)    
		printf("%d\n",digit);    
    }
    return 0;
}
第二种
#include <stdio.h>
int main() {
    printf("2\n");
    int digit;
    int divisor;
    for (digit = 3; digit <= 100; digit += 2) 
    {        
        for (divisor = 2; divisor < (digit / 2); divisor ++) 
        {                    
			if (digit % divisor == 0)
            break;
        }
		if(divisor >= digit/2)    
		printf("%d\n",digit);    
    }
    return 0;
}
第三种
#include <stdio.h>
#include <math.h>
int main() {
    printf("2\n");
    int digit;
    int divisor;
    for (digit = 3; digit <= 100; digit += 2) 
    {        
        for (divisor = 2; divisor < sqrt(digit); divisor ++) 
        {                    
			if (digit % divisor == 0)
            break;
        }
		if(divisor > sqrt(digit))    
		printf("%d\n",digit);    
    }
    return 0;
}

判断质数

题目要求:对于给定的一个大于 1 的正整数 N,判定它是否是一个质数

我们输入一个整数,如果要判断它不是一个质数,我们可以列出某一个范围的整数,通过求余数的方式判断这些列出的数字是不是给出整数的因数。如果发现任何一个因数,我们就可以确认它不是质数,输出 NO 后直接 break 就可以了(不用再判断后续的整数了)。如果所有的列出的数都被判断不是它的因数,则可以最后输出 YES

#include <stdio.h>
#include <math.h>
int main() {
    int digit;
    int divisor;
    int flag;
    scanf("%d", &digit);
    if (digit < 2)
    {
        printf("NO\n");
        return 0;
    }
    if (digit == 2)
    {
        printf("YES\n");
        return 0;
    }
    for (divisor = 2; divisor <= sqrt(digit); divisor ++) 
        {                    
			if (digit % divisor == 0)
            {
                flag = 0;
                break;
            }
            if(divisor > sqrt(digit))
            {
                flag = 1;
            }
        }
    if(flag == 1)
        printf("YES\n");
    if(flag == 0)
        printf("NO\n");
    return 0;
}

小于指定值的质数

题目要求:请对于给定的一个大于 1的正整数 N,按从小到大的顺序输出所有小于等于它的质数

思路与输出质数相似,将第一层循环的上限改为输入即可。

#include <stdio.h>
#include <math.h>
int main() {
    int digit;
    int divisor;
    int num;
    scanf("%d", &num);
    printf("2\n");
    if(num > 2)
    {
        for (digit = 3; digit <= num; digit += 2) 
        {        
            for (divisor = 2; divisor < sqrt(digit); divisor ++) 
            {                    
			    if (digit % divisor == 0)
                break;
            }
		    if(divisor > sqrt(digit))    
		    printf("%d\n",digit);    
        }
    }    
    return 0;
}

指定范围的质数

题目要求:请对于给定的一个大于1的正整数N和一个大于1的正整数M,N一定大于M(N,M均小于等于10的6次方),请按从小到大的顺序输出所有小于等于N且大于等于M的质数

这里我们采用质数筛法(sieve method)的方式。与之前的对每一个数字依次判断是否为质数的方式不同,筛法的思想是“标记出所有非质数,输出所有没被标记的数字”。这里以“输出15以内大于1的所有质数”为例,示例代码如下:

#include <stdio.h>
int main() {
    int n = 15;
    int mark[16] = {
        1, 1, 0, 0,
        0, 0, 0, 0,
        0, 0, 0, 0,
        0, 0, 0, 0
    };
    int c;
    int j;

    for (c = 2; c * c <= n; c++) {
		if (mark[c] != 1) {
            for (j = 2; j <= n / c; j++) {
                mark[c * j] = 1;
            }
        }
    }
	for (c = 2; c <= n; c++) {
        if (mark[c] != 1) {
            printf("%d\n", c);
        }
    }
    return 0;
}

这里采用此筛法,并使用string.h中的memset函数设置数组内的元素。本题代码如下:

#include <stdio.h>
#include <string.h>
int n = 1000000;
int mark[1000001];
int main() {
    int c;
    int i, j;
    int N;
    int M;
    scanf("%d%d", &N, &M);
    memset(mark, 0, sizeof(mark));
    mark[0] = 1;
    mark[1] = 1;
    for (c = 2; c * c <= n; c++) {
        if (mark[c] != 1) {
            for (i = 2; i <= N / c; i++) {
                mark[c * i] = 1;
            }
        }
    }
    for (j = M; j <= N; j++) {
        if (mark[j] != 1) {
            printf("%d\n",j);
        }
    }
    return 0;
}

总结

有关质数的问题(判断质数、打印质数、统计质数个数等)我们可以采用筛法减少复杂度(有一种埃氏筛法可以减少时间复杂度,可以了解)。可以将判断质数功能独立为质数检验函数。当然,检验范围缩小至2到平方根可以大大减小算法的复杂度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值