代码意识流——花朵数问题(四)

本文前一部分的链接
http://www.cnblogs.com/KBTiller/archive/2011/06/01/2065569.html

10.考虑求各位数N次方的和
  有两个问题需要考虑,第一是存放各位数N次方的和的变量定义的位置,其次是这个变量的类型。
  变量定义的位置,首先考虑在xunhuan()函数定义形参的地方,把这个函数定义为
    static void xunhuan( const int gssx /*个数上限*/,   
                          const int sz /*关于哪个数字*/,
                                某类型 和)
    {
    }   

  这样的话在qiongju()函数中应该这样调用
    xunhuan( WEISHU , JINZHI-1 ,(某类型) 0 ) ;
  然而由于这个数据的类型不可能是简单的基本类型,所以如果编译器不支持C99的话,就必须首先在qiongju()函数中定义一个变量,把这个变量初始化为0之后再用这个变量作为实参进行调用:
    extern void qiongju( void )
    {
      某类型 和 = {0} ;  
      xunhuan( WEISHU , JINZHI-1 , 和 ) ;
    }
  除了初始化为0之后做实参,“和”这个变量在qiongju()函数中根本没有其他任何用处,所以在qiongju()函数中定义这个变量恐怕难免给人一种牵强的感觉,当然,如果不太讲究的话,这样写也可以。
  C99中有一种东西叫Compound literal,这种东西的本质就是一种复杂数据类型的常量。如果可以使用这种东东,就可以避免牵强地去定义变量。
  由于C99的实现不是那么普遍,所以还是选择把这个变量定义在xunhuan()内部。这个变量用于递归调用中传递数据,因此必须是static类别。

    static void xunhuan( const int gssx /*个数上限*/, 
                              const int sz /*关于哪个数字*/) 
    {
       static 某类型 he ;//=0
   
      ……
    }

11.测试
  先考虑求各位数一次方的和,这时可以把“和”的类型暂时确定为int

static void xunhuan( const int gssx /*个数上限*/, 
                     const int sz /*关于哪个数字*/)  
{
   static int he = 0 ;//=0  //static 某类型 he ;//=0
   int he_ = he  ;    //记录累加前的值 

   if( sz > 0 ){
      int i;
      for( i = 0 ; i <= gssx ; i++ ){
         printf("%d*%d +" , i , sz );
         he += i * sz  ;             // 每次调用都从he开始累加 
         xunhuan( gssx - i , sz - 1 );
         he = he_ ;                  //恢复原来的值 
      }
   }
   else{
      he += gssx * sz ;
      printf("%d*%d = %d" , gssx , sz , he );
      putchar('\n');//<=>验算<=>记录结果
   }
}

  运行结果正确。


12.一个修正
  突然觉得前面把 #include "0_问题.h" 写在 1_MAIN.h 和 2_穷举.h 中很傻,这条预处理命令应该写在 1_MAIN.c 和 2_穷举.c 中。分别移动一下,然后编译,运行,通过。移动成功

13.添加新类型
  由于“和”这个变量可能需要存储一个很大的整数值,所以普通的整数类型是不能胜任的,需要自己定义新的类型。设新的类型的名字为 DASHU

修改 
       

static void xunhuan( const int gssx /*个数上限*/, 
                     const int sz /*关于哪个数字*/)  
{
   static DASHU he    ; // =0   待完成  
   DASHU        he_   ; // = he 待完成 

   if( sz > 0 ){
      int i;
      for( i = 0 ; i <= gssx ; i++ ){
         printf("%d*%d +" , i , sz );
         //待修改 he += i * sz  ;             // 每次调用都从he开始累加 
         xunhuan( gssx - i , sz - 1 );
         //待修改 he = he_ ;                  //恢复原来的值 
      }
   }
   else{
      //待修改 he += gssx * sz ;
      //待修改 printf("%d*%d = %d" , gssx , sz , he );
      putchar('\n');//<=>验算<=>记录结果
   }
}   

  因为涉及到这种新类型的运算较多,这些运算大多需要通过定义函数来重新定义,因此把这种类型的定义及函数统一写在其他模块。

修改

/*2_穷举.h*/

#ifndef QIONGJU_H
#define QIONGJU_H 

              
/**************************类型定义**************************/ 
   #include "3_大数.h" 


/**************************函数原型**************************/ 
   
   extern void qiongju( void );

    
#endif // QIONGJU_H

 

  在工程中添加“3_大数.h”源文件,最初的内容为

/*3_大数.h*/

#ifndef DASHU_H
#define DASHU_H 
            
/**************************类型定义**************************/ 
   typedef DASHU ; 

/**************************函数原型**************************/ 
   
     
#endif // DASHU_H

  随手编译了一下,居然没有任何错误。(没想到这也能编译,typedef 有这种用法吗?这个编译器太善解人意了)

14.大数类型

  有很多表示大数的方案。最不可取的大概是用字符串存储各位数字的方案,因为会涉及到字符与数值之间的反复转换。除了输入输出比较容易写,这种方案没有什么优势。
  所以采用用一个int存储一位数的方案,WEISHU位数就构成一个数组,各位数字按从低到高顺序存储(下标为0的元素存储个位)。因为运算不能保证一定不超过WEISHU位,这种数据结构应该能表示溢出,即超过WEISHU位时的表示。这个可以通过使得存储最高位数字的元素大于等于JINZHI来表示。
这样DASHU类型可以定义为
typedef struct {
                        int gw_sz[WEISHU] ;//gw_sz[0]为个位,gw_sz[WEISHU-1]为最高位
                       } 
                       DASHU ;             //gw_sz[WEISHU-1]的值大于等于JINZHI表示溢出

  之所用struct 把这个数组包装起来是因为注意到了xunhuan()函数中有这种类型数据的赋值运算。结构体类型的数据可以直接赋值,数组要完成同样的功能写起来就复杂多了。

修改

/*3_大数.h*/

#ifndef DASHU_H
#define DASHU_H 

#include "0_问题.h"             //DASHU用到了WEISHU             

/**************************类型定义**************************/ 
//gw_sz[0]为个位,gw_sz[WEISHU-1]为最高位
//gw_sz[WEISHU-1]的值大于等于JINZHI表示溢出
   typedef struct { 
                   int gw_sz[WEISHU] ; 
                  }  
                  DASHU ;          

/**************************函数原型**************************/ 
   
     
#endif // DASHU_H

然后返回xunhuan()函数改写代码。

15.改写代码

static DASHU he    ; // =0   待完成
现在可以补全了
static DASHU he = { { 0 } }   ;

DASHU        he_   ; // = he 待完成    //记录累加前的值
现在可以直接
DASHU        he_ = he ;   //记录累加前的值

//待修改 he = he_ ;                  //恢复原来的值
现在也可以直接
he = he_ ;                  //恢复原来的值


下面要做的事情是改写
//待修改 he += i * sz  ;
这需要对DASHU这种类型定义加法运算

posted @ 2011-06-02 14:19  键盘农夫  阅读(1662)  评论(2编辑  收藏  举报