zoukankan      html  css  js  c++  java
  • 代码意识流——花朵数问题(九)

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

    23.拆除脚手架
    把为测试写的多余的代码删除;重新审视代码
    extern SF   chaoguo_W ( const DASHU * const );
    改名为
    extern SF   ds_chaoguo_W ( const DASHU * const ); 

    extern SF   buzu_W    ( const DASHU * const );
    改名为
    extern SF   ds_buzu_W    ( const DASHU * const );

    extern void qiu_sz_gs ( int (*)[JINZHI] , const DASHU * const ) ;
    改名为
    extern void ds_qiu_sz_gs ( int (*)[JINZHI] , const DASHU * const ) ;

    extern SF   xiaoyu    ( const DASHU * const , const DASHU * const ) ;
    改名为
    extern DX   ds_bijiao ( const DASHU * const , const DASHU * const ) ;
    修改了函数原型并重新进行了定义

    View Code
    /*0_问题.h*/

    #ifndef WENTI_H
    #define WENTI_H

    #define QIUJIE //求解21位问题
    //#define CESHI //进行测试

    #ifdef CESHI
    //测试

    #define JINZHI 10 //十进制
    #define WEISHU 3 //3位花朵数
    #define N WEISHU //幂次==位数

    #endif //CESHI

    #ifdef QIUJIE
    //求解

    #define JINZHI 10 //十进制
    #define WEISHU 21 //位数
    #define N WEISHU //幂次==位数

    #endif //QIUJIE

    #endif // WENTI_H
    View Code
    /*1_MAIN.h*/

    #ifndef MAIN_H
    #define MAIN_H

    /**************************类型定义**************************/

    /**************************函数原型**************************/

    #include
    <stdlib.h> //system()
    #include "2_穷举.h" //qiongju()
    #include "4_结果.h" //shuchu()

    #endif // MAIN_H
    View Code
    /*
    Name:花朵数问题
    Author:键盘农夫
    Date:2011,5,30
    Description:
    */

    #include
    "1_MAIN.h"
    #include
    "0_问题.h"

    #ifdef CESHI
    //测试

    int main( void )
    {
    system(
    "PAUSE");
    return 0;
    }

    #endif //CESHI

    #ifdef QIUJIE
    //求解

    int main( void )
    {
    qiongju();
    //求解:穷举<=>验算<=>记录结果
    shuchu(); //输出

    system(
    "PAUSE");
    return 0;
    }

    #endif //QIUJIE
    View Code
    /*2_穷举.h*/

    #ifndef QIONGJU_H
    #define QIONGJU_H

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

    /**************************函数原型**************************/

    extern void qiongju( void );
    #include
    <stdlib.h> //malloc()
    #include <string.h> //memcmp()
    #include "4_结果.h" //jilu()

    #endif // QIONGJU_H
    View Code
    /*2_穷举.c*/

    #include
    "2_穷举.h"
    #include
    "0_问题.h"

    typedef unsigned
    int SHUZI_GESHU[JINZHI];
    //SHUZI_GESHU[d]存储出现在数字组合中数字d的个数

    typedef DASHU SHUJUBIAO[JINZHI
    -1][WEISHU + 1];
    //0*(JINZHI-1)^N 1*(JINZHI-1)^N ……WEISHU*(JINZHI-1)^N
    //0*(JINZHI-2)^N 1*(JINZHI-2)^N ……WEISHU*(JINZHI-1)^N
    //……
    //0*(1)^N 1*(1)^N ……WEISHU*(1)^N

    static void xunhuan(const int , const int , DASHU (*)[WEISHU + 1] ) ;
    static void jianli_sjb ( SHUJUBIAO * * ); //建立数据表
    static SF wenhe( SHUZI_GESHU * const , const DASHU * const);

    // 判断*p_he中各数字的个数与*p_sz_gs是否吻合
    static SF wenhe( SHUZI_GESHU * const p_sz_gs ,
    const DASHU * const p_he )
    {
    int sz_gs_he[JINZHI] = { 0 }; //"和"中各数字的个数

    if( ds_chaoguo_W(p_he) == SHI //超过W位||不足W位
    || ds_buzu_W (p_he) == SHI ){
    return FOU ;
    }

    ds_qiu_sz_gs(
    &sz_gs_he , p_he ); //求"和"中各数字的个数

    if ( memcmp ( sz_gs_he , *p_sz_gs , sizeof sz_gs_he )==0 ){
    return SHI ;
    }

    return FOU ;
    }

    //建立数据表
    static void jianli_sjb ( SHUJUBIAO * * p_p_sjb )
    {
    if( (* p_p_sjb = malloc(sizeof(SHUJUBIAO)) ) == NULL ){
    exit(
    !EXIT_SUCCESS);
    }
    {
    int i , j ;
    for( i = 0 ; i < JINZHI - 1 ; i ++){
    ds_fuzhi(
    *( * * p_p_sjb + i ) + 0 , 0 );//第一列为0
    ds_fuzhi( *( * * p_p_sjb + i ) + 1 , 1 );//第二列先赋值为1
    for( j = 0 ; j < N ; j ++ ){ //求N次幂
    ds_chengyi( *( * * p_p_sjb + i ) + 1 , JINZHI - 1 - i );
    }
    for( j = 2 ; j <= WEISHU ; j ++ ){
    (
    *( * * p_p_sjb + i ))[j] = (*( * * p_p_sjb + i ))[j-1] ;
    ds_jiaru (
    *( * * p_p_sjb + i ) + j , *( * * p_p_sjb + i ) + 1 ) ;
    }
    }
    }
    }

    extern void qiongju( void )
    {
    SHUJUBIAO
    *p_sjb = NULL ;

    jianli_sjb (
    & p_sjb ); //建立数据表
    xunhuan( WEISHU , JINZHI-1 , *p_sjb ) ;
    free ( p_sjb );
    }

    static void xunhuan( const int gssx /*个数上限*/ ,
    const int sz /*关于哪个数字*/,
    DASHU (
    *p_hang)[WEISHU + 1] /*指向一行数据*/)
    {
    static DASHU he = { { 0 } } ;//用于累加"和"
    static SHUZI_GESHU sz_gs ;
    DASHU he_
    = he ; //记录累加前的值

    if( sz > 0 ){
    int i;
    for( i = 0 ; i <= gssx ; i++ ){
    sz_gs[sz]
    = i ; //记录数字的个数
    ds_jiaru ( &he , *p_hang + i ) ;
    xunhuan( gssx
    - i , sz - 1 , p_hang + 1 ); //选取下一个数字^N的倍数
    he = he_ ; //恢复原来的值
    }
    }
    else{
    sz_gs[sz]
    = gssx ; //记录数字的个数
    if( wenhe ( & sz_gs , &he ) == SHI ){ //验算两者是否"吻合"
    jilu( & he ); //<=>记录结果
    }
    }
    }
    View Code
    /*3_大数.h*/

    #ifndef DASHU_H
    #define DASHU_H

    #include
    "0_问题.h" //DASHU用到了WEISHU
    typedef enum {
    DAYU ,
    //大于
    DENGYU , //等于
    XIAOYU //小于
    } DX ;

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

    /**************************函数原型**************************/

    extern void ds_fuzhi ( DASHU * const , const int ) ;
    extern void ds_shuchu ( const DASHU * const ) ;
    extern void ds_jiaru ( DASHU * const , const DASHU * const ) ;
    extern void ds_chengyi( DASHU * const , const int );
    extern SF ds_chaoguo_W ( const DASHU * const );
    extern SF ds_buzu_W ( const DASHU * const );
    extern void ds_qiu_sz_gs ( int (*)[JINZHI] , const DASHU * const ) ;
    extern DX ds_bijiao ( const DASHU * const , const DASHU * const ) ;

    #endif // DASHU_H
    View Code
    /*3_大数.c*/
    #include
    "3_大数.h"

    static void ds_jinwei ( DASHU * const );

    extern DX ds_bijiao ( const DASHU * const p_ds1, const DASHU * const p_ds2)
    {
    int *t1 = p_ds1-> gw_sz , * w1 = t1 + WEISHU -1 ;
    int *t2 = p_ds2-> gw_sz , * w2 = t2 + WEISHU -1 ;

    while( w1 > t1 ){
    if( *w1 < *w2 ){
    return XIAOYU ;
    }
    if( *w1-- > *w2-- ){
    return DAYU ;
    }
    }
    if( *w1 < *w2 ){
    return XIAOYU ;
    }
    if( *w1> *w2 ){
    return DAYU ;
    }
    return DENGYU ;
    }

    //统计*p_he中的各数字个数=> *p_sz_gs
    extern void ds_qiu_sz_gs( int (*p_sz_gs)[JINZHI] , const DASHU * const p_he )
    {
    int * t = p_he->gw_sz ;
    while( t < p_he->gw_sz + WEISHU ){
    (
    *( *p_sz_gs + *t++ ))++ ;//(*p_sz_gs)[*t++] ++ ;
    }
    }

    //判断是否不足WEISHU
    extern SF ds_buzu_W(const DASHU * const p_ds)
    {
    if(p_ds->gw_sz[WEISHU-1] == 0 ){
    return SHI ;
    }
    return FOU ;
    }

    //判断是否超过WEISHU
    extern SF ds_chaoguo_W(const DASHU * const p_ds)
    {
    if(p_ds->gw_sz[WEISHU-1] >=JINZHI ){
    return SHI ;
    }
    return FOU ;
    }

    //* p_ds *= cs
    extern void ds_chengyi( DASHU * const p_ds , const int cs )
    {
    int * t = p_ds->gw_sz ;
    while( t < p_ds->gw_sz + WEISHU ){
    *t++ *=cs ;
    }
    ds_jinwei ( p_ds );
    }

    //进位
    static void ds_jinwei ( DASHU * const p_ds )
    {
    int * t = p_ds->gw_sz , * const w = t + WEISHU - 1 ;
    while( t < w ){
    *( t + 1 ) += * t / JINZHI ;
    * t ++ %= JINZHI ;
    }
    }

    // *p_he += *p_js
    extern void ds_jiaru ( DASHU * const p_he , const DASHU * const p_js )
    {
    int *he_t = p_he->gw_sz , * const he_w = he_t + WEISHU ;
    const int *js_t = p_js->gw_sz ;
    while( he_t < he_w ){
    *he_t++ += *js_t++ ;
    }
    ds_jinwei ( p_he );
    }

    //输出(若输出10以上进制需要补充代码)
    extern void ds_shuchu( const DASHU * const p_ds )
    {
    int * const t = p_ds->gw_sz , *w = t + WEISHU - 1 ;
    while( w > t && *w == 0 ){ //高位0不输出
    w--;
    }
    while( w > t ){
    printf(
    "%d" , * w -- );
    }
    printf(
    "%d\n" , * t ) ;
    }

    //在*p_ds中写入n
    extern void ds_fuzhi ( DASHU * const p_ds , const int n )
    {
    p_ds
    ->gw_sz[0] = n ;
    //可能有进位,同时把高位写为0
    {
    int *t = p_ds->gw_sz , //指向 p_ds->gw_sz[0]
    *w = t + WEISHU - 1 ; //指向 p_ds->gw_sz[WEISHU-1]
    while( t < w ){
    *( t + 1 ) = * t / JINZHI ;
    * t ++ %= JINZHI ;
    }
    }
    }
    View Code
    /*4_结果.h*/

    #ifndef JIEGUO_H
    #define JIEGUO_H

    /**************************类型定义**************************/
    #include
    "3_大数.h"
    typedef
    struct jd {
    DASHU hds;
    //花朵数
    struct jd *xyg; //下一个
    }
    JIEDIAN;
    #include
    "常用.h"
    /**************************函数原型**************************/

    extern void jilu( DASHU * );
    #include
    "3_大数.h" //xiaoyu()
    #include <stdlib.h> //malloc(),NULL
    extern void shuchu(void);

    #endif // JIEGUO_H
    View Code
    /*4_结果.c*/
    #include
    "4_结果.h"

    static JIEDIAN *tou = NULL ; //记录链表的第一个节点

    extern void shuchu(void)
    {
    while( tou != NULL ){
    JIEDIAN
    *p_xyg = tou-> xyg ;
    ds_shuchu(
    &tou->hds);
    free( tou );
    tou
    = p_xyg ;
    }
    tou
    = NULL ;
    }

    extern void jilu( DASHU *p_ds )
    {
    JIEDIAN
    **p_t = &tou ;
    JIEDIAN
    *p_jd = NULL ;

    if((p_jd = malloc( sizeof (JIEDIAN ) )) == NULL ){ // 添加节点
    printf("无法存储");
    exit(
    !EXIT_SUCCESS);
    }
    else{
    p_jd
    ->hds = *p_ds ; //把结果写入节点
    }

    while ( *p_t != NULL
    && ( ds_bijiao(&(*p_t)->hds , p_ds ) == XIAOYU ) ) { //寻找恰当的位置
    p_t = &(*p_t)->xyg ;
    }

    //加入到链表中
    p_jd -> xyg = * p_t ;
    * p_t = p_jd ;

    }

    24.性能改善
    这个程序的运行时间主要决定于穷举的过程,所以性能改善显然应该主要考虑这个过程。其中可能的主要因素有:递归调用参数传递、大数运算、算法等。

    25.算法改进

    在递归过程中考虑一旦累加的“和”应经超过位数或不可能达到位数就提前结束递归

    View Code
    static void xunhuan( const int gssx /*个数上限*/ ,
    const int sz /*关于哪个数字*/,
    DASHU (
    *p_hang)[WEISHU + 1] /*指向一行数据*/)
    {
    static DASHU he = { { 0 } } ;//用于累加"和"
    static SHUZI_GESHU sz_gs ;
    DASHU he_
    = he ; //记录累加前的值

    if( sz > 0 ){
    int i;
    for( i = 0 ; i <= gssx ; i++ ){
    sz_gs[sz]
    = i ; //记录数字的个数
    ds_jiaru ( &he , *p_hang + i ) ;
    if( ds_chaoguo_W( &he ) == SHI ){
    return ;
    }
    if(i==gssx && (ds_buzu_W ( &he) == SHI) ){
    return ;
    }
    xunhuan( gssx
    - i , sz - 1 , p_hang + 1 ); //选取下一个数字^N的倍数
    he = he_ ; //恢复原来的值
    }
    }
    else{
    sz_gs[sz]
    = gssx ; //记录数字的个数
    if( wenhe ( & sz_gs , &he ) == SHI ){ //验算两者是否"吻合"
    jilu( & he ); //<=>记录结果
    }
    }
    }

    这种办法运行时间只减少了2~3%。

    26.不带参数的递归

    将xunhuan()中的运算移动到qiongju(),运行时间减少8%左右。

    View Code
    /*2_穷举.c*/

    #include
    "2_穷举.h"
    #include
    "0_问题.h"

    #define KAISHI JINZHI
    #define JIESHU 0

    typedef unsigned
    int SHUZI_GESHU[JINZHI];
    //SHUZI_GESHU[d]存储出现在数字组合中数字d的个数

    typedef DASHU SHUJUBIAO[JINZHI
    -1][WEISHU + 1];
    //0*(JINZHI-1)^N 1*(JINZHI-1)^N ……WEISHU*(JINZHI-1)^N
    //0*(JINZHI-2)^N 1*(JINZHI-2)^N ……WEISHU*(JINZHI-1)^N
    //……
    //0*(1)^N 1*(1)^N ……WEISHU*(1)^N

    //static void xunhuan(const int , const int , DASHU (*)[WEISHU + 1] ) ;
    static void jianli_sjb ( SHUJUBIAO * * ); //建立数据表
    static SF wenhe( SHUZI_GESHU * const , const DASHU * const);
    static void zhunbei( int * const , SHUJUBIAO ** const , int * const , DASHU (*(*))[ WEISHU + 1 ]);
    static void shouwei( SHUJUBIAO * * const , int * const , DASHU * const );

    // 判断*p_he中各数字的个数与*p_sz_gs是否吻合
    static SF wenhe( SHUZI_GESHU * const p_sz_gs ,
    const DASHU * const p_he )
    {
    int sz_gs_he[JINZHI] = { 0 }; //"和"中各数字的个数

    if( ds_chaoguo_W(p_he) == SHI //超过W位||不足W位
    || ds_buzu_W (p_he) == SHI ){
    return FOU ;
    }

    ds_qiu_sz_gs(
    &sz_gs_he , p_he ); //求"和"中各数字的个数

    if ( memcmp ( sz_gs_he , *p_sz_gs , sizeof sz_gs_he )==0 ){
    return SHI ;
    }

    return FOU ;
    }

    //建立数据表
    static void jianli_sjb ( SHUJUBIAO * * p_p_sjb )
    {
    if( (* p_p_sjb = malloc(sizeof(SHUJUBIAO)) ) == NULL ){
    exit(
    !EXIT_SUCCESS);
    }
    {
    int i , j ;
    for( i = 0 ; i < JINZHI - 1 ; i ++){
    ds_fuzhi(
    *( * * p_p_sjb + i ) + 0 , 0 );//第一列为0
    ds_fuzhi( *( * * p_p_sjb + i ) + 1 , 1 );//第二列先赋值为1
    for( j = 0 ; j < N ; j ++ ){ //求N次幂
    ds_chengyi( *( * * p_p_sjb + i ) + 1 , JINZHI - 1 - i );
    }
    for( j = 2 ; j <= WEISHU ; j ++ ){
    (
    *( * * p_p_sjb + i ))[j] = (*( * * p_p_sjb + i ))[j-1] ;
    ds_jiaru (
    *( * * p_p_sjb + i ) + j , *( * * p_p_sjb + i ) + 1 ) ;
    }
    }
    }
    }

    static void zhunbei( int * const p_gssx ,
    SHUJUBIAO
    ** const p_p_sjb,
    int * const p_sz ,
    DASHU (
    *(*p_p_hang))[ WEISHU + 1 ])
    {
    * p_gssx = WEISHU ;
    jianli_sjb ( p_p_sjb ) ;
    //建立数据表
    * p_p_hang = **p_p_sjb ;
    (
    *p_sz)-- ;

    }

    static void shouwei( SHUJUBIAO ** const p_p_sjb ,
    int * const p_sz ,
    DASHU
    * const p_he )
    {
    free (
    *p_p_sjb ) ;
    *p_p_sjb = NULL ;

    * p_sz = KAISHI ;

    ds_fuzhi( p_he ,
    0 );

    }

    extern void qiongju( void )
    {
    static int gssx , sz = JINZHI ;
    static SHUJUBIAO *p_sjb = NULL ;
    static DASHU (*p_hang)[ WEISHU + 1 ] ;
    static DASHU he = { { 0 } } ; //用于累加"和"
    static SHUZI_GESHU sz_gs ;

    switch( sz ){
    case KAISHI:
    zhunbei(
    & gssx , & p_sjb , & sz , & p_hang ); //准备工作
    qiongju() ;
    shouwei(
    &p_sjb , & sz , &he );//收尾工作
    return ;
    default :
    {
    DASHU he_
    = he ; //记录累加前的值
    int gssx_ = gssx ;
    int i ;
    for( i = 0 ; i <= gssx_ ; i ++ ){
    ds_jiaru (
    &he , *p_hang + i ) ;
    p_hang
    ++ ;
    sz_gs[sz
    --] = i ;
    gssx
    = gssx_ - i ;
    qiongju() ;
    p_hang
    -- ;
    sz
    ++ ;
    gssx
    = gssx_ ;
    he
    = he_ ;
    }
    }
    return ;
    case JIESHU:
    sz_gs[sz]
    = gssx ;
    if( wenhe ( & sz_gs , &he ) == SHI ){ //验算两者是否"吻合"
    jilu( & he ); //<=>记录结果
    }
    return ;
    }
    }

    27.减少不必要的大数运算

    在递归过程中有些地方的加数为0,没必要。去除这些不必要的加法运算

    View Code
    static void xunhuan( const int gssx /*个数上限*/ ,
    const int sz /*关于哪个数字*/,
    DASHU (
    *p_hang)[WEISHU + 1] /*指向一行数据*/)
    {
    static DASHU he = { { 0 } } ;//用于累加"和"
    static SHUZI_GESHU sz_gs ;
    DASHU he_
    = he ; //记录累加前的值

    if( sz > 0 ){
    int i;
    for( i = 0 ; i <= gssx ; i++ ){
    sz_gs[sz]
    = i ; //记录数字的个数
    if(i!=0){
    ds_jiaru (
    &he , *p_hang + i ) ;
    }
    xunhuan( gssx
    - i , sz - 1 , p_hang + 1 ); //选取下一个数字^N的倍数
    he = he_ ; //恢复原来的值
    }
    }
    else{
    sz_gs[sz]
    = gssx ; //记录数字的个数

    if( wenhe ( & sz_gs , &he ) == SHI ){ //验算两者是否"吻合"
    jilu( & he ); //<=>记录结果
    }
    }
    }

    很意外,运行时间居然减少了20%左右。

    由此可见,大数的运算对性能影响最大,最初的设计用一个int存储一位是有些过于奢侈了。

    28.采用新的数据结构

    由于前面结果的提示,DASHU采用更紧凑的形式,一个int存储7位,运行时间可减少50%以上

    致谢:从与CU的蔡万钊、A.com、koolcoy (娶妻求贤)等网友的讨论中得到许多有益的启发,在此致谢。

    (完)

  • 相关阅读:
    Spring源码解析 | 第一篇 :IntelliJ IDEA2019.3编译Spring5.3.x源码
    Mybatis和Mybatis-Plus时间范围查询,亲测有效
    Centos7增加磁盘空间并挂载目录(VMware)
    Docker添加TLS认证修复2375端口暴露引发的漏洞
    【动态规划】0-1背包问题原理和实现
    c#日期格式化(关于12小时制和24小时制)
    JS日期时间格式化
    子页面iframe如何调用 父页面的方法 或者对象(基于layui框架)
    js把文字复制到粘贴板
    理解sql server STUFF函数
  • 原文地址:https://www.cnblogs.com/KBTiller/p/2078457.html
Copyright © 2011-2022 走看看