教娃编程实录1:质数判断与分解质因数

求出100到200之间的所有质数

子任务1:如何判断一个整数是否为质数

为摸索出判断一个自然数是否为质数的算法,首先让娃用纸和笔去判断151是否为质数。她是这样做的:

151 ÷ 2 = 75......1

151 ÷ 3 = 50......1

151 ÷ 5 = 30......1

151 ÷ 7 = 21......4

151 ÷ 11 = 13......8

151 ÷ 13 = 11......8

至此,她做出判断:151是一个质数。问其故,答:试到除数大于商还不整除,就可以确定是质数了。

然其说,开始编码。

子任务2:编码与调试

经若干次提点、编译和调试,得到如下可运行代码:

 1 #include <stdio.h>
 2 
 3 int main()
 4 {
 5     int num = 99;
 6     while (num < 200)
 7     {
 8         num = num + 1;
 9         int d = 1; // divisor
10         int q = 0; // quotient
11         int r = 0; // remainder
12         while (true)
13         {
14             d = d + 1;
15             r = num % d;
16             q = num / d;
17             if (r == 0)
18             {
19                 break;
20             }
21             if (d >= q)
22             {
23                 printf("%d is a prime.\n", num);
24                 break;
25             }
26         } // end of inner loop
27     } // end of outer loop
28 
29     return 0;
30 }

运行得到符合预期的结果:

子任务3:把质数判断写成一个函数bool is_prime(int num)

稍加提点,经编译、调试完成is_prime函数以及改写的main函数:

 1 bool is_prime(int num)
 2 {
 3     int d = 1; // divisor
 4     int q = 0; // quotient
 5     int r = 0; // remainder
 6     while (true)
 7     {
 8         d = d + 1;
 9         r = num % d;
10         q = num / d;
11         if (r == 0)
12         {
13             return false;
14         }
15         if (d >= q)
16         {
17             return true;
18         }
19     }
20 }
21 
22 int main()
23 {
24     int x = 99;
25     while (x < 200)
26     {
27         x = x + 1;
28         if (is_prime(x))
29         {
30             printf("%d is a prime.\n", x);
31         }
32     }
33     return 0;
34 }

运行结果和之前完全一致。

求出0到100之间的所有质数

娃这次反应很快,改了main函数开头两行代码里的两个数值:

    int x = -1;
    while (x < 100)

并表示肯定没问题。

运行结果的头几行如下:

1 is a prime.
3 is a prime.
5 is a prime.
...
问:可有什么问题?

答:哦,1搞错了。

还有什么搞错的吗?

没有了。

2呢?

2,哦,2也搞错了。

看看怎么出错的吧。

……

又经提点和尝试,得到如下没有错误的is_prime函数:

 1 bool is_prime(int num)
 2 {
 3     if(num == 1)
 4     {
 5         return false;
 6     }
 7     if (num == 2)
 8     {
 9         return true;
10     }
11     int d = 1; // divisor
12     int q = 0; // quotient
13     int r = 0; // remainder
14     while (true)
15     {
16         d = d + 1;
17         r = num % d;
18         q = num / d;
19         if (r == 0)
20         {
21             return false;
22         }
23         if (d >= q)
24         {
25             return true;
26         }
27     }
28 }

对100到200之间的所有整数分解质因数

 要求输出格式如下:

100 = 2 * 2 * 5 * 5

101 = 101

102 = 2 * 3 * 17

...

子任务1:分解质因数的算法

娃胸有成竹地说:还用判断质数的方法,碰到整除就得到num = d * q,再分别对d和q继续用同样的办法分解质因数。

我:这么说是没错的,而且前面除数逐次加一的尝试方法碰到整除时d一定是质数,下一步只需对q继续分解质因数。

子任务2:编码与调试

理解d一定会是质数后,娃开始尝试直接在main函数添加代码。尝试了一阵发现太难了。求提点。

提点1:写一个函数void factorize(int num),对传入的num分解质因数

提点2:对每行输出结果做拆解,开头的“num = ”还有末尾的换行在main里写代码来做,中间的质因数分解结果输出由factorize函数来做

很快main函数出来了:

 1 int main()
 2 {
 3     int x = 99;
 4     while (x < 200)
 5     {
 6         x = x + 1;
 7         printf("%d = ", x);
 8         factorize(x);
 9         printf("\n");
10     }
11     return 0;
12 }

factorize函数在提点和帮写中也出来了:

 1 void factorize(int x)
 2 {
 3     int d = 1;
 4     int q = 0;
 5     int r = 0;
 6     while (true)
 7     {
 8         d = d + 1;
 9         q = x / d;
10         r = x % d;
11         if (r == 0)
12         {
13             printf("%d * ", d);
14             factorize(q);
15             return;
16         }
17         if (q < d)
18         {
19             printf("%d.", x);
20             return;
21         }
22     }
23 }

当然,作为初学者,娃对factorize内部有对factorize自身的调用难免会有一些困惑。在几番调试运行之下,慢慢也便懂得了这种称作递归的用法。

运行,节选输出结果如下:

100 = 2 * 2 * 5 * 5.
101 = 101.
102 = 2 * 3 * 17.
103 = 103.
104 = 2 * 2 * 2 * 13.
......
124 = 2 * 2 * 31.
125 = 5 * 5 * 5.
126 = 2 * 3 * 3 * 7.
127 = 127.
128 = 2 * 2 * 2 * 2 * 2 * 2 * 2 * 1.
......

查看问题,发现128的分解结果里末尾多了“ * 1”。娃思考后判断问题出在factorize(2)。

提议把质因数分解的范围调整到1到9,修改mian函数里头两行代码,如下:

    int x = 0;
    while (x < 9)

运行,输出结果如下:

1 = 1.
2 = 2 * 1.
3 = 3.
4 = 2 * 2 * 1.
5 = 5.
6 = 2 * 3.
7 = 7.
8 = 2 * 2 * 2 * 1.
9 = 3 * 3.

验证了娃的判断,提点参看之前写is_prime函数碰到的缺陷和修改办法,很快找到了改正办法,即在factorize函数开头增加如下代码即可:

    if (x == 2)
    {
        printf("%d.",x);
        return;
    }

子任务3:factorize(0)会怎么样

在main函数把第一行代码改为:

    int x = -1;

重新运行,先是出现如下的结果输出:

过一阵,又会看到如下的窗口提示:

点击“中断”按钮,进到下图所示的调用堆栈:

简单跟娃解释一下代码在指定的地方(第84行)出现factorize(0)无限嵌套调用factorize(0)的问题,导致factorize(0)永远执行不完(无法走到第85行的代码),不必过多地解释堆栈溢出是怎么回事。

随后就是要如何解决factorize(0)走不到出口的问题,办法很简单,把前面对付factorize(2)的缺陷的代码稍作修改即可:

    if (x == 2 || x == 0)
    {
        printf("%d.",x);
        return;
    }

课后作业

1、factorize函数里的if (q < d)是否可以换成if (q <= d),为什么?

2、factorize函数对350分解质因数的过程中,在找出2和5两个质因数后,对最后的35分解质因数时,还是会从除数2开始尝试能否整除,有没有改进的办法,如何改进?

提点:增加一个参数

3、如何实现一个求阶乘值的函数

 

posted on 2020-07-25 19:27  readalps  阅读(812)  评论(0编辑  收藏  举报

导航