算法P--打印500个素数的表

We can face our problem.

We can arrange such facts as we have

with order and method.

我们能够面对我们的问题。

我们可以解决它们,

因为我们有规则和方法。

目录

一、数学准备

二、算法分析

三、算法实现


一、数学准备

        1.数学归纳法

                设 P(n) 是关于整数 n 的一个命题。例如,P(n) 可以是类似 “n 乘以 (n + 3) 是一个偶数” 这样的一个命题。假设我们要证明:对于所有的正整数 n,P(n) 这个命题都是成立的,也就是说,对于所有的正整数 n,P(n) 为真。实现这一点的一个重要方法是:

(a)给出 P(1) 为真的证明;

(b)假设 P(1)、P(2)、P(3) .... P(n) 都为真,给出 P(n + 1) 也为真的证明;这个证明应该对任何正整数 n 都为真。

        2.每个大于 1 的整数都可以写成一个或多个素数的乘积(一个素数被认为是 1 和它自身的乘积)。

证明过程:

        当 n = 2 时,2 是素数,且 2 = 1 * 2,结论显然成立;

        假设当 n = 2,3,4 .... k 时,结论成立。

        当 n = k + 1 时,考虑下列两种情况:

        (1)k + 1 是素数,结论成立;

        (2)k + 1 是合数

                合数的定义:数是指在大于1的整数中除了能被1和本身整除外,还能被其他数(0除外)整除的数。

           由合数的定义可得,存在大于 1 且小于 k +1 的整数 n,m,使得 n * m = k + 1。

            显然,n,m 大于 1 且小于 k + 1,符合假设的条件,则 n,m 可以分解为一个或多个素数的乘积,所以 k + 1 也能。

             得证。

 二、算法分析

        本算法分为两个不同的部分:步骤 P1 ~ P8 准备一个500个素数的内部表,而 P9 ~ P11 准备是以 10 列,每列 50 个数的表的形式打印出答案。算法的后边部分用了两个 “缓冲区”,在其中形成行的映像;在打印一个缓冲区内容的同时,往另一个缓冲区送入数。

        P1.【开始造表】置 Prime[0] = 2,N = 3,J = 1;(在这个算法中,N 取遍作为素数候选者的奇数;J 记住迄今为止已经求出了多少个素数。)

        P2.【N 是素数】置 J = J + 1,Prime[J] = N;

        P3.【找到 500 个了?】如果 J = 500,转到 P9;

        P4.【增加 N】置 N = N + 2;

        P5.【K = 1】置 K = 1;(Prime[K] 将取遍 N 的所有素因子,K 之所以不从 0 开始取,是因为 Prime[0] 等于 2,而我们的 N 取的是奇数,所以 K 从 1 开始取)

       P6.【N / Prime[K]?】以 N 除以 Prime[K],设 Q 为商,R 为余数。如果 R = 0(因此 N 不是素数),则转 P4;

       P7.【Prime[K] 足够大了吗?】如果 Q <= Prime[K],转 P2;(在这样的情况下,N 必定为素数)

       P8.【K 加 1】K + 1,并转 P6;

       P9.【打印标题】现在我们已经做好打印表的准备,把打印机推进到下一页,置 Buffer[0] 为标题行并打印此行。置 B = 1,M = 0;

       P10.【设置行】以适当格式把 Prime[M],Prime[50 + M],... Prime[450 + M] 放进 Buffer[B] 中;

       P11.【打印行】打印 Buffer[B];置 B = 1 - B(因此转到另一个缓冲区);且 M + 1,若 M <= 50,返回 P10,否则算法终止。

        WARNING:因为 Knuth 是使用一种叫做 MIXAL 的汇编语言来实现算法P,而我们是使用 C 语言来实现,所以可以省去 P9 ~ P11。

三、算法实现

#include <stdio.h>

#define Numbers 500

int cycles;

int prime_list(int* prime, int num) {
    int n, j, k;
    int q, r;
    int skip = 0;

    prime[0] = 2;
    n = 3;

    for (j = 1; j < num; j++) {
        prime[j] = n;

        while (n += 2) {

            for (k = 2; ; k++) {

                cycles += 1;
                q = n / prime[k - 1];
                r = n % prime[k - 1];

                if (r == 0) {
                    break;
                }

                if (q <= prime[k - 1]) {
                    skip = 1;
                    break;
                }
            }

            if (skip) {
                skip = 0;
                break;
            }
        }
    }
    return 0;
}

int printf_prime(int* prime, int num) {
    int i;
    printf("First\t\tFive\t\tHunderd\t\tPrimes");

    for (i = 0; i < num; i++) {
        if (i % 10 == 0) {
            printf("\n");
        }
        printf("%7ld", prime[i]);
    }
    printf("\n");

    return 0;
}


int main() {

    int Primes[Numbers];

    prime_list(Primes, Numbers);
    printf_prime(Primes, Numbers);
    printf("\ncycles: %d\n", cycles);
    return 0;
}

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值