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

本文详细介绍了针对特定大数问题求解算法的优化策略,包括但不限于代码重构、性能改进、算法调整以及数据结构优化,以显著提高程序运行效率。通过减少不必要的计算、采用更紧凑的数据结构以及改进递归过程,实现运行时间大幅减少,尤其在大数运算方面取得了显著成效。文章还提及了后续可能的优化方向和改进方法。

本文前一部分的链接
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 ) ;
修改了函数原型并重新进行了定义

ContractedBlock.gif ExpandedBlockStart.gif 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
ContractedBlock.gif ExpandedBlockStart.gif 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
ContractedBlock.gif ExpandedBlockStart.gif 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
ContractedBlock.gif ExpandedBlockStart.gif 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
ContractedBlock.gif ExpandedBlockStart.gif 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 ); // <=>记录结果
}
}
}
ContractedBlock.gif ExpandedBlockStart.gif 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
ContractedBlock.gif ExpandedBlockStart.gif 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 ;
}
}
}
ContractedBlock.gif ExpandedBlockStart.gif 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
ContractedBlock.gif ExpandedBlockStart.gif 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.算法改进

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

ContractedBlock.gif ExpandedBlockStart.gif 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%左右。

ContractedBlock.gif ExpandedBlockStart.gif 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,没必要。去除这些不必要的加法运算

ContractedBlock.gif ExpandedBlockStart.gif 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 (娶妻求贤)等网友的讨论中得到许多有益的启发,在此致谢。

(完)

转载于:https://www.cnblogs.com/KBTiller/archive/2011/06/11/2078457.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值