鸡窝里飞出伪凤凰

本文深入剖析了一个常见的代码设计问题,即在main函数中过度集中导致的代码混乱。通过具体例子展示了如何通过代码重构,如合理布局函数调用、简化变量使用和优化循环条件等手段,提升代码的可读性和维护性。着重强调了结构化编程原则的重要性,提倡自顶向下的思考方式,以写出优雅简洁的代码。

  不少初学者在写代码时喜欢一main()到底——把所有的代码都写在main()函数中。代码在作茧自缚的main()函数“迷宫”中像没头苍蝇一样左冲右突,写到哪儿算哪儿。忙活了半天之后,终于成功“突围”——可以运行程序了,然后就一脸轻松。但是却把main()函数弄得凌乱不堪,一地鸡毛,形同鸡窝。
  这种代码是一种“爬行”式思维的产物,是人类思维的一种返祖现象。人类在学会直立行走之前就是按照这种方式思考的。俗话说,站得高才能看得远。而匍匐在地上爬行,只能得到脏、乱、差的代码。
  这种代码有一种变形,就是在一地鸡毛的main()中可能会冷不丁地突然窜出一个令人眼前一亮的自定义函数调用,犹如一地鸡毛的鸡窝里仿佛要飞出一只金凤凰似的。这样的代码多半出自那种半生不熟的新手,他们并不是自觉自愿地而往往是被强迫地使用一下自定义函数。这就使得代码产生了一种滑稽的喜感,犹如一只小狗被要求站立起来作揖一样,站立一秒钟之后,很快就会重新伏到地上继续爬行。下面的代码就是一例:

/*例8.8 将数组a中的n个整数按相反顺序存放*/
#include <stdio.h>
int main( void )
{void inv(int x[],int n);
int i, a[10]={3,7,9,11,0,6,7,5,4,2};
printf("The original array:\n");
for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");
inv(a,10);
printf("The array has been vnverted:\n");
for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");
return 0;
}

void inv(int *x,int n)
{int *p,temp,*i,*j,m=(n-1)/2;
i=x;j=x+n-1;p=x+m;
for(;i<=p;i++,j--)
{temp=*i;*i=*j;*j=temp;}
return ;
}

      ————谭浩强 ,《C程序设计》(第四版),清华大学出版社, 2010年6月,p241
  首先来看main():
  一进门就可以看到main()函数的头上顶着一条条幅——不是“北京欢迎您”,而是函数类型声明“void inv(int x[],int n);”。这样做的效果是使得main()显得更加凌乱,并且有让main()函数独霸inv()函数使用权之嫌。因为其他代码中的其他函数若需要调用inv()函数还得重新进行函数类型声明。这种不加思索地把函数类型说明随便塞在某个地方的做法,绝不可能是出于事先周密思考权衡的结果,其原因估计多半只是为了对付编译器的类型检查而已。和下面的写法对比一下,就不难发现函数类型声明塞在函数内部的荒谬性:

View Code
#include <stdio.h>
void inv(int x[],int n);
int main( void )
{
/*……*/
}

  显然,后者不但能完全实现样本代码的功能,而且main()更清爽,此外代码的其他部分若需要调用inv()也不需要无谓地再次写函数类型声明了。
再继续往下看

View Code
printf("The original array:\n");
for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");

  一地鸡毛!在main()这样重要的地方忙活鸡毛蒜皮是庸人最擅长的事情。其原因在于:思想一直是在代码层面上爬行,而又缺乏代码重构的意识。这是违背结构化程序设计原则的一个报应。结构化程序设计要求“自顶向下”地思考,要达到这个境界,前提是要“站直了,别趴下”。一直趴着绝对写不出优雅,简洁的代码。优秀的代码首先要站得高,其次很忌讳把事做“绝”。再往下看

View Code
inv(a,10);

  前后都是一地鸡毛,唯独这个充分且简洁的函数调用犹如金凤一样摆出了一副展翅欲飞的优美姿态。赞一个!再继续看

View Code
printf("The array has been vnverted:\n");
for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");

  天哪!竟然写出了和前面一模一样的代码!对于任何合格的程序员来说,这绝对是一种耻辱。这和车轱辘话来回说没什么区别。这使得main()即使苍蝇没来下蛆就已经脏乱得腐败不堪了。当然,有些人对此是不介意的。“不干不净,吃了没病”,你没办法对那些在垃圾桶里寻找食物的人说清楚什么叫做卫生。“不干不净,吃了没病”这种想法在程序设计界的翻版“只要程序能运行”,你同样也无法和有些人说清楚代码为什么应该简洁优美,这是没有办法的事情。但是,如果把这种丑陋的恶习写在教科书里,那就成了一种教唆,我个人认为应该判刑。因为这就和《卫生》课本里示范如何食用地沟油异曲同工。
  再往后,就是那只从main()中飞出来的inv()函数的定义了。

View Code
void inv(int *x,int n)
{int *p,temp,*i,*j,m=(n-1)/2;
i=x;j=x+n-1;p=x+m;
for(;i<=p;i++,j--)
{temp=*i;*i=*j;*j=temp;}
return ;
}

  首先,把“int *p,temp,*i,*j,m=(n-1)/2;”这几个变量定义紧密地写在“{”之后是一种令人作呕的风格。此外,令人吃惊的是,实现如此简单的功能,居然一口气使用了5个“蒙头盖脸”的变量——你从名字上绝对不可能看出这些变量是做什么用的。这也是趴在地上思考的成果。由于事先缺乏充分且有高度的思考,就免不了“东一榔头西一棒子”地滥用变量(反正变量不要钱)。同样是由于缺乏缜密的思考,所以使用这些变量只是由于一时兴起,事后代码作者自己恐怕也弄不清楚究竟这些变量的真正含义。实际上根本不需要这么多的变量。
  首先来看p,它的作用仅仅是用来表示x+m这个值,显然毫无必要,代码完全可以写成

View Code
void inv(int *x,int n)
{
int temp,*i,*j,m=(n-1)/2;
i=x;j=x+n-1;
for(;i<=x+m;i++,j--)
{temp=*i;*i=*j;*j=temp;}
return ;
}

  再看m,它只是记录了(n-1)/2这个在代码中从没有改变过的值而已,因而也没有必要。

View Code
void inv(int *x,int n)
{
int temp,*i,*j;
i=x;j=x+n-1;
for(;i<=x+(n-1)/2;i++,j--)
{temp=*i;*i=*j;*j=temp;}
return ;
}

  现在对代码走查一下,假设n的值为3,那么i,j的变化情况为:
  i             j          
  x          x+2        
  x+1     x+1
  不难发现,当i变化成x+1时,程序进行了一次毫无意义的交换。这说明“i<=x+(n-1)/2”这个表达式不但在写法上过于啰嗦,在逻辑上也很非常蹩脚。实际上只要简单地         

View Code
void inv(int *x,int n)
{
int temp,*i,*j;
for(i=x,j=x+n-1 ; i < j ;i++,j--)
{temp=*i;*i=*j;*j=temp;}
return ;
}

就可以了。
  最后,

View Code
{temp=*i;*i=*j;*j=temp;}

不但风格上奇丑无比,而且同样犯了把事做“绝”的毛病——绝则错。
  所以,尽管从main()这个鸡窝里飞了出来,但inv()只是一只“伪”凤凰而已。
  最后,对这段代码重构如下:

#include <stdio.h>

void inv(int [],int );
void output( int [] , int , char *);
void swap ( int * , int * );

int main( void )
{
	int a[10]={3,7,9,11,0,6,7,5,4,2};

	output(a,10,"The original array:");
 
	inv(a,10);
 
	output(a,10,"The array has been inverted:");
 
	return 0;
}

void output( int x[] , int n , char *s )
{
	int i;

	puts(s);
	
	for( i = 0 ; i < n ; i++ )
		printf("%d ", x[i]);

	putchar('\n');   
}

void inv(int *p_begin , int n )
{
	int *p_end = p_begin + n - 1 ;

	while ( p_end > p_begin )
		swap ( p_end -- , p_begin ++ );
}

void swap ( int *p , int *q )
{
	int temp  ;
	temp = *p ;
	*p = *q   ;
	*q = temp ;
}

 

 

标题SpringBoot智能在线预约挂号系统研究AI更换标题第1章引言介绍智能在线预约挂号系统的研究背景、意义、国内外研究现状及论文创新点。1.1研究背景与意义阐述智能在线预约挂号系统对提升医疗服务效率的重要性。1.2国内外研究现状分析国内外智能在线预约挂号系统的研究与应用情况。1.3研究方法及创新点概述本文采用的技术路线、研究方法及主要创新点。第2章相关理论总结智能在线预约挂号系统相关理论,包括系统架构、开发技术等。2.1系统架构设计理论介绍系统架构设计的基本原则和常用方法。2.2SpringBoot开发框架理论阐述SpringBoot框架的特点、优势及其在系统开发中的应用。2.3数据库设计与管理理论介绍数据库设计原则、数据模型及数据库管理系统。2.4网络安全与数据保护理论讨论网络安全威胁、数据保护技术及其在系统中的应用。第3章SpringBoot智能在线预约挂号系统设计详细介绍系统的设计方案,包括功能模块划分、数据库设计等。3.1系统功能模块设计划分系统功能模块,如用户管理、挂号管理、医生排班等。3.2数据库设计与实现设计数据库表结构,确定字段类型、主键及外键关系。3.3用户界面设计设计用户友好的界面,提升用户体验。3.4系统安全设计阐述系统安全策略,包括用户认证、数据加密等。第4章系统实现与测试介绍系统的实现过程,包括编码、测试及优化等。4.1系统编码实现采用SpringBoot框架进行系统编码实现。4.2系统测试方法介绍系统测试的方法、步骤及测试用例设计。4.3系统性能测试与分析对系统进行性能测试,分析测试结果并提出优化建议。4.4系统优化与改进根据测试结果对系统进行优化和改进,提升系统性能。第5章研究结果呈现系统实现后的效果,包括功能实现、性能提升等。5.1系统功能实现效果展示系统各功能模块的实现效果,如挂号成功界面等。5.2系统性能提升效果对比优化前后的系统性能
在金融行业中,对信用风险的判断是核心环节之一,其结果对机构的信贷政策和风险控制策略有直接影响。本文将围绕如何借助机器学习方法,尤其是Sklearn工具包,建立用于判断信用状况的预测系统。文中将涵盖逻辑回归、支持向量机等常见方法,并通过实际操作流程进行说明。 一、机器学习基本概念 机器学习属于人工智能的子领域,其基本理念是通过数据自动学习规律,而非依赖人工设定规则。在信贷分析中,该技术可用于挖掘历史数据中的潜在规律,进而对未来的信用表现进行预测。 二、Sklearn工具包概述 Sklearn(Scikit-learn)是Python语言中广泛使用的机器学习模块,提供多种数据处理和建模功能。它简化了数据清洗、特征提取、模型构建、验证与优化等流程,是数据科学项目中的常用工具。 三、逻辑回归模型 逻辑回归是一种常用于分类任务的线性模型,特别适用于二类问题。在信用评估中,该模型可用于判断借款人是否可能违约。其通过逻辑函数将输出映射为0到1之间的概率值,从而表示违约的可能性。 四、支持向量机模型 支持向量机是一种用于监督学习的算法,适用于数据维度高、样本量小的情况。在信用分析中,该方法能够通过寻找最佳分割面,区分违约与非违约客户。通过选用不同核函数,可应对复杂的非线性关系,提升预测精度。 五、数据预处理步骤 在建模前,需对原始数据进行清理与转换,包括处理缺失值、识别异常点、标准化数值、筛选有效特征等。对于信用评分,常见的输入变量包括收入水平、负债比例、信用历史记录、职业稳定性等。预处理有助于减少噪声干扰,增强模型的适应性。 六、模型构建与验证 借助Sklearn,可以将数据集划分为训练集和测试集,并通过交叉验证调整参数以提升模型性能。常用评估指标包括准确率、召回率、F1值以及AUC-ROC曲线。在处理不平衡数据时,更应关注模型的召回率与特异性。 七、集成学习方法 为提升模型预测能力,可采用集成策略,如结合多个模型的预测结果。这有助于降低单一模型的偏差与方差,增强整体预测的稳定性与准确性。 综上,基于机器学习的信用评估系统可通过Sklearn中的多种算法,结合合理的数据处理与模型优化,实现对借款人信用状况的精准判断。在实际应用中,需持续调整模型以适应市场变化,保障预测结果的长期有效性。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值