搜索
查看: 2209|回复: 9
打印 上一主题 下一主题

【第五章第6节】动手试一试 题解

[复制链接]
跳转到指定楼层
楼主
发表于 2013-11-4 01:00:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
测试编译器 clang 3.1
编译参数 -ansi -pedantic -Werror

如果你需要让程序最后暂停,那么自己加system("pause")之类的语句吧,所有题解都相同,以下不再重复说明。

首先是最平庸的解法
  1. #include <stdio.h>

  2. int is_prime(int);

  3. int main(void)
  4. {
  5.   int i, j;
  6.   for(i=4; i!=100+2; i+=2){
  7.   /* 只用检验偶数,所以i每次自增2 */
  8.     int upper = i / 2;
  9.   /* c = a + b = b + a,只用检查一半的就可以了 */
  10.     printf("%d", i);
  11.     for(j=2; j <= upper; ++j)
  12.       if(is_prime(j) && is_prime(i-j))
  13.         printf("=%d+%d", j, i-j);
  14.   /* 换行的另一种写法,少打几个字 */
  15.     puts("");
  16.   }
  17.   return 0;
  18. }

  19. /* 判断一个数字是不是质数,基本上和书上的做法一样 */
  20. int is_prime(int n)
  21. {
  22.   int i;
  23.   int upper = n / 2;
  24.   for(i=2; i<=upper; ++i)
  25.     if(n % i == 0)
  26.       return 0;
  27.   return 1;
  28. }
复制代码
推荐
发表于 2014-11-21 17:36:26 | 只看该作者
参考LZ的第一个解,自己修改了例题,得到的习题的解答,不考虑效率等因素,纯粹的小白答案。
#include <stdio.h>
#include <stdlib.h>
int main()
{
    int k,a,b,i,fa,fb;
    for(k=4;k<=100;k=k+2)
    {
        printf("%d",k);
        for(a=2;a<=k/2;a++)
        {
             //判断a是否为质数
            fa =0;
            for(i=2;i<=a-1;i++)
            {
                if(a % i == 0)
                {
                    fa=1;
                    break;
                }            
            }
            
            if(fa==0)//如果a为质数
            {
                 b=k-a;
                fb=0;
                for(i=2;i<=b-1;i++)
                {
                    if(b%i == 0)
                    {
                          fb=1;
                          break;
                    }
                }
               
                if(fb==0) //如果b也是质数
                {
                       printf("=%d+%d",a,b);
                }   
            }
        }
        printf("\n");
    }
system("pause");
return 0;
}
沙发
 楼主| 发表于 2013-11-4 01:44:47 | 只看该作者
上面的做法不是很好,存在大量的重复计算
例如分解10,程序会验证 2+8 3+7 4+6 5+5
于是就要试除计算2是不是质数,8是不是质数,3是不是质数,7是不是质数……
而这些计算中有些已经在之前的计算中做过了,例如分解8的时候,已经验证过2是不是质数,6是不是质数

所以可以把所有质数缓存起来,代码如下
  1. #include <stdio.h>

  2. void init(void);
  3. int is_prime(int);

  4. int prime_table[50];
  5. /* 用来存放质数,1-100之间的质数有多少个?你可能记得是25个,不记得也不要紧,肯定不会超过50个 */
  6. int prime_num = 0;
  7. /* 如果不记得,那么就可以在计算的时候统计一下 */

  8. int main(void)
  9. {
  10.   int i, j;
  11.   init();
  12.   for(i=4; i!=100+2; i+=2){
  13.     int upper = i / 2;
  14.     printf("%d", i);
  15.     for(j=2; j <= upper; ++j)
  16.       if(is_prime(j) && is_prime(i-j))
  17.         printf("=%d+%d", j, i-j);
  18.     puts("");
  19.   }
  20.   return 0;
  21. }

  22. void init()
  23. {
  24.   int i, j;
  25.   int pos = 0;
  26.   /* 下一个算出来的质数,存放在质数表的哪个位置? */
  27.   for(i=2; i!=100; ++i){
  28.     int upper = i/2;
  29.     int is_prime = 1;
  30.     for(j=2; j<=upper; ++j)
  31.       if(i % j == 0){
  32.         is_prime = 0;
  33.         break;
  34.       }
  35.     if(is_prime){
  36.     /* 如果是质数,那么记录到质数表中,更新下一个写入的位置,然后质数的总数加一 */
  37.       prime_table[pos] = i;
  38.       ++pos;
  39.       ++prime_num;
  40.     }
  41.   }
  42. }

  43. int is_prime(int n)
  44. {
  45.   int pos;
  46.   for(pos=0; pos!=prime_num; ++pos)
  47.     if(n == prime_table[pos])
  48.       return 1;
  49.   /* 扫描质数表,如果这个数字存储在质数表中,那么它就是质数,否则就不是 */
  50.   return 0;
  51. }
复制代码
板凳
 楼主| 发表于 2013-11-4 02:11:05 | 只看该作者
上面的做法仍然有改进空间,例如把质数表的搜索改成2分搜索;线性搜索最坏要25次,而二分搜索只要5次就可以了。
另外试除到n/2是比较慢的做法,筛质数可以参考 http://bbs.ahalei.com/thread-2961-1-2.html
但是100以内的数字实在太少,改进也难以察觉效果
不过最后还是写一个我自己比较满意的版本
  1. #include <stdio.h>

  2. void init(void);
  3. int is_prime(int);

  4. int prime_table[50];
  5. int prime_num = 0;

  6. int main(void)
  7. {
  8.   int i, j;
  9.   init();
  10.   for(i=4; i!=100+2; i+=2){
  11.     int upper = i / 2;
  12.     printf("%d", i);
  13.     for(j=2; j <= upper; ++j)
  14.       if(is_prime(j) && is_prime(i-j))
  15.         printf("=%d+%d", j, i-j);
  16.     puts("");
  17.   }
  18.   return 0;
  19. }

  20. void init()
  21. {
  22.   int i, j;
  23.   int pos = 0;
  24.   int div[] = {2, 3, 5, 7};
  25.   /* 筛法,将100以内的整数用2,3,5,7筛一遍,剩下的就是质数 */
  26.   int buf[101] = {1, 1, 0};
  27.   for(i=0; i!=4; ++i){
  28.     int d = div[i];
  29.     buf[d] = 1;
  30.     for(j=d*d; j<101; j+=d)
  31.       buf[j] = 1;
  32.   }
  33.   for(i=0; i!=4; ++i)
  34.     prime_table[pos++] = div[i];
  35.   for(i=3; i<101; i+=2)
  36.     if(buf[i] == 0){
  37.       prime_table[pos++] = i;
  38.       prime_num += 1;
  39.     }
  40.   prime_num += 4;
  41. }

  42. int is_prime(int n)
  43. {
  44.   /* 二分搜索 */
  45.   int upper = prime_num-1;
  46.   int lower = 0;
  47.   while(upper >= lower){
  48.     int mid = (upper + lower) / 2;
  49.     if(prime_table[mid] > n)
  50.       upper = mid - 1;
  51.     else if(prime_table[mid] < n)
  52.       lower = mid + 1;
  53.     else
  54.       return 1;
  55.   }
  56.   return 0;
  57. }
复制代码
地板
发表于 2014-5-2 18:43:57 | 只看该作者
楼主是写出来了.但是用了很多书上跟本没有提到的知识.我想只是看了<<啊哈C>>这本书的人看不懂.我现在也看不懂.所以这个答案没什么意义.可不可以用书上提到的知识来实现啊?让我们看看过程.学到些东西.
5#
 楼主| 发表于 2014-5-2 21:22:42 | 只看该作者
kuaile1210 发表于 2014-5-2 18:43
楼主是写出来了.但是用了很多书上跟本没有提到的知识.我想只是看了这本书的人看不懂.我现在也看不懂.所以这 ...

请至少说下哪些部分看不懂,哪些部分用了书上没有提到的知识,这样才可能解决问题
6#
发表于 2014-7-6 22:51:05 | 只看该作者
rosynirvana 发表于 2014-5-2 21:22
请至少说下哪些部分看不懂,哪些部分用了书上没有提到的知识,这样才可能解决问题

LZ大大写的程序都要比较后面才能学到了吧?,
应该根据我们的进程写一段代码,
我们不可能看完整本书才来做这些题目的对吧?
7#
 楼主| 发表于 2014-7-7 02:49:31 | 只看该作者
xu1123 发表于 2014-7-6 22:51
LZ大大写的程序都要比较后面才能学到了吧?,
应该根据我们的进程写一段代码,
我们不可能看完整本书才来 ...

所以您哪里看不懂了请直接说
9#
发表于 2015-11-9 16:54:28 | 只看该作者
LS的是最接近书本进度的写法
10#
发表于 2018-2-26 12:03:36 | 只看该作者
snowlele 发表于 2014-11-21 17:36
参考LZ的第一个解,自己修改了例题,得到的习题的解答,不考虑效率等因素,纯粹的小白答案。
#include
# ...

这个方法很棒呀,非常简洁,对我们小白来说可读性高。而且是用学过的方法实现的。LZ大大的代码中的二分搜索和缓存,prime-,buf[j]等等。真是令我们一头雾水,一脸懵逼
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

广播台
特别关注
快速回复 返回顶部 返回列表