逻辑顺序体现了人的思维的条理性和严密性。合理的顺序可以提升解决问题的品质,相反,混乱的顺序很容易导致各种错误的发生。在分支结构中经常需要面临各种优化逻辑顺序的问题。
人在思考问题时,一般总会对各种最可能发生的情况做好准备,这叫做“有备而来”。分支结构中各种条件根据情况的先后、轻重来排定顺序。如果把最可能的条件放在前面,把最不可能的条件放在后面,这样程序在执行时总会按照代码先后顺序逐一检测所有条件,直到发现匹配的条件时才停止继续检测。如果把最可能的条件放在前面,就等于降低了程序的检测次数,自然也就提升了分支结构的执行效率,避免空转,这在大批量数据检测中效果非常明显。例如,对于一个论坛系统来说,普通会员的数量要远远大于版主和管理员的数量。换句话说,大部分登录的用户都是普通会员,如果把普通会员的检测放在分支结构的前面,就会减少计算机检测的次数。
if优化目标:最小化找到正确分支之前所判断条件体的数量。if优化方法:将最常见的条件体放在首位。例如:
if(value<5){
//do something
}else if(value>5&&value<10){
//do something
}else{
//do something
}
这段代码只有在value值经常小于5时才是最优的。如果value经常大于或等于10,那么在进入正确分支之前,必须两次运算条件体,导致表达式的平均运行时间增加。if中的条件体应当总是按照从最大概率到最小概率的顺序排列,以保证理论运行速度最快。
另外一种减少条件判断数量的方法:将if编写成一系列嵌套结构。使用一个单独的一长串的if结构通常导致运行缓慢,因为每个条件体都要被计算,例如:
if(value==0){
return result0;
}else if(value==1){
return result1;
}else if(value==2){
return result2;
}else if(value==3){
return result3;
}else if(value==4){
return result4;
}else if(value==5){
return result5;
}else if(value==6){
return result6;
}else if(value==7){
return result7;
}else if(value==8){
return result8;
}else if(value==9){
return result9;
}else{
return result10;
}
在这个if结构中,所计算的条件体的最大数目是10。如果假设value的值在0~10之间均匀分布,那么会增加平均运行时间。为了减少条件判断的数量,可重写为一系列嵌套结构,例如:
if(value<6){
if(value<3){
if(value==0){
return result0;
}else if(value==1){
return result1;
}else{
return result2;
}
}else{
if(value==3){
return result3;
}else if(value==4){
return result4;
}else{
return result5;
}
}
}else{
if(value<8){
if(value==6){
return result6;
}else{
return result7;
}
}else{
if(value==8){
return result8;
}else if(value==9){
return result9;
}else{
return result10;
}
}
}
重写if结构后,每次抵达正确分支时最多通过4个条件判断。新的if结构使用二分搜索法将值域分成了一系列区间,然后逐步缩小范围。当数值范围分布在0~10时,此代码的平均运行时间大约是前面代码的一半。此方法适用于需要测试大量数值的情况,而相对离散值来说switch更合适。
当然,在性能影响不是很大的情况下,遵循条件检测的自然顺序会更容易阅读。例如,对于检测周一到周五值日任务安排的分支结构来说,虽然周五的任务比较重要,但是这类任务有着明显的顺序,安排顺序结构还是遵循它的自然逻辑比较好。如果打乱条件的顺序,把周五的任务安排在前面,对于整个分支结构的执行性能没有太大的帮助,并且不方便阅读代码。考虑到这一点,按自然顺序来安排结构会更富可读性。
应注意分支之间的顺序优化,当然在同一个条件表达式内部也应该考虑逻辑顺序问题。在执行逻辑“与”或逻辑“或”运算时,有可能会省略右侧表达式的计算,如果希望不管右侧表达式是否成立都进行计算,就应该考虑逻辑顺序问题。例如,有两个条件a和b,其中条件a多为true,b就是一个必须执行的表达式,那么下面的逻辑顺序设计就欠妥当:
if(a&&b){
}
如果条件a为false,则JavaScript会忽略表达式b的计算。如果b表达式影响到后面的运算,那么不执行表达式b自然会对后面的逻辑产生影响,这时可以采用下面的逻辑结构,在if结构前先执行表达式b,这样即使条件a的返回值为false,也能够保证表达式b被计算。
var c=b;
if(a&&b){
}