帮初学者改代码——playerc之“练习:求完数问题”(下)

前文链接:帮初学者改代码——playerc之“练习:求完数问题”(上)

  再来看看be_ferfect()应该如何改。

  be_ferfect()函数的功能是判断number是否为完数,同时把因子对写入divisers数组。以28这个完数为例,在数组中将依次写入

  1 28 2 14 4 7

  输出时则按要求依大小次序输出 1 2 4 7 14。先从前跳到后,到头之后掉头,再从后跳到前。

  这种写入的方式决定了输出代码写起来要困难一些。如果希望输出写得容易些的话,写入时就必须改变这种图省事的办法。

  有很多种方案可选:

  第一种方案,从小到大写

1
2
3
4
5
6
7
8
9
10
11
int divisers_count = 1 ;
for ( i = 2 ; i < number ; ++ i ){
      if (!( number % i)){
 
         divisers[divisers_count ++ ] = i;
         sum += i;
 
         if ( sum > number )
            return false;
      }
}

  这显然简洁多了。作者没有考虑这种方法应该是有自己的想法,估计是认为一对儿一对儿的写更快些。对比一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int divisers_count = 2 ;
 
for ( i = 2 , i_max = sqrt(number)+1 ; i < i_max ; ++ i ){
      if (!(number % i)){
 
         divisers[divisers_count ++ ] = i;
         sum += i;
          
         diviser = number / i ;
         if ( diviser != i ) {
           divisers[ divisers_count ++ ] = diviser;
           sum += diviser;
         }
          
         if ( sum > number )
          return false;
      }      
}

  作者的写法做了大约2√n次除法、求余和不等于运算,而第一种方案要做n-1次除法。作者的写法虽然复杂,但优势还是有一些的。   

  第二种方案,用两个数组存储因子

  1   2   4

  28 14 7

  这样即保留了作者算法的优势,输出的代码也比较容易写。但这要整个地修改代码的基本数据结构,改动比较大。所以这里就不用了。

  第三种方案,从数组两头向中间存储

  1 2 4 0 0 0 …… 7 14

  这种方案,虽然看起来有点别扭,但读写数组都更容易些,也不需要改动数据结构,权衡之下,是唯一较为可取的方案。

  采用这种方案的代码如下: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <stdio.h>
#include <stdbool.h>
 
bool be_ferfect( int , int * , int * );
void output( int [] , int );
 
#define TOP (10000)
#define DIVISERS_MAX_LENGTH  ((3+1)*(1+1)*(1+1)*(1+1)*(1+1))
 
int main( void
    int number;
   
    for( number = 2 ; number < ( TOP + 1 ) ; ++number ){
        
         int divisers[DIVISERS_MAX_LENGTH] = { 1 } ;
          
         if ( be_ferfect( number , divisers ,
                                   divisers + DIVISERS_MAX_LENGTH - 1 ) ){
             printf("%d ,Its factors are : ", number) ;                        
             output ( divisers , DIVISERS_MAX_LENGTH ) ; 
         }
    }
  
  return 0;
}
 
bool be_ferfect( int number , int * p_b , int * p_e )
{
   int i ;
   int sum = * p_b ++ ;
    
   for ( i = 2 ; i * i < number ; ++ i ){
      if ( number % i != 0 )
         continue
          
      sum +=  ( * p_b ++ = i ) + ( * p_e -- = number / i ) ;
       
      if ( sum > number )
         return false;
   }
    
   if ( i * i == number )
       sum += ( * p_b ++ = i) ;
    
   return sum == number ;
}
 
void output ( int divisers[] , int size )
{
   int i ;
    
   for ( i = 0 ; i < size ; i ++ ){
        
      if ( divisers[i] == 0 )
         continue ;
 
      printf ("%d ",divisers[i]);
   }
   putchar('\n');
}

 (完)

posted @   garbageMan  阅读(983)  评论(2编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
历史上的今天:
2010-11-01 一个凶险的BUG
点击右上角即可分享
微信分享提示