正确的优化分段函数形式的多重分支代码

来源:互联网 发布:房产经纪人开单软件 编辑:程序博客网 时间:2024/05/09 23:50

File:      fastmif.txt
Name:      正确的优化分段函数形式的多重分支代码
Author:    zyl910
Blog:      http://blog.csdn.net/zyl910/
Version:   V1.00
Updata:    2006-10-13


一、基本代码
  有时候,我们会碰上这样的多重分支代码:
char szbuf[10];
if     (score >= 90) strcpy(szbuf, "优");
elseif (score >= 80) strcpy(szbuf, "良");
elseif (score >= 60) strcpy(szbuf, "及格");
else                 strcpy(szbuf, "不及格");

  这样的代码无疑是很低效的,怎么优化呢?


二、错误的优化

  很多书上说可以根据频率分布来优化代码,比如及格的人最多时,这样编写代码:
char szbuf[10];
if     (score >= 60 && score < 80) strcpy(szbuf, "及格");
elseif (score >= 80 && score < 90) strcpy(szbuf, "良");
elseif (score >= 90)               strcpy(szbuf, "优");
else                               strcpy(szbuf, "不及格");

  可以看出,这样做实际上增加了判断次数。只有在分支极多时,该优化方案才比上一个好。


三、正确的优化

  现在都是做整数比较,速度非常快的,反而会因判断之后的跳转指令堵塞流水线而影响效率。所以正确的优化代码应该是这样的:
const char szlist[][10] = {"不及格", "及格", "良", "优"};
char szbuf[10];
int i=0;
i += ( score >= 60 ); // #1
i += ( score >= 80 ); // #2
i += ( score >= 90 ); // #3
strcpy(szbuf, szlist[i]);

  当score小于60时,#1、#2、#3均不成立,所以 i = i + 0 + 0 + 0 = i + 0 = 0
  当score在[60,80)区间时,#1成立,所以 i = i + 1 + 0 + 0 = i + 1 = 1
  当score在[80,90)区间时,#1、#2均成立,所以 i = i + 1 + 1 + 0 = i + 2 = 2
  当score大于90时,#1、#2、#3均成立,所以 i = i + 1 + 1 + 1 = i + 3 = 3
  最后用索引i从szlist中得到具体数据。


四、全面优化

  看出来了吧,对于这种分段函数形式的多重分支代码,可以根据数据特点来优化。所以,我们还可以更进一步,将程序改成表格驱动的形式:
const char szlist[][10] = {"不及格", "及格", "良", "优"};
const char idxlist[] = {60, 80, 90};

  然后我们在idxlist表中搜索score,得到索引,再用索引从szlist得到数据。
  这样无论以后的需求如何改变,我们只需要修改这两行代码就行了。

  这时,可能会有人问了:如果分支极多怎么办,难道还是一个一个的比较?现在流行面向对象编程,很多时候进行的是对象比较,而对象比较的速度很慢,而现在又搞这么多比较,那不是影响效率吗?

  注意我刚才说过什么——“在idxlist表中搜索score”,现在idxlist中的数据是有序的,当然用二分法查找啊!
  具体说起来,由于我们在小于60(idxlist[0])时返回0、在大于等于60(idxlist[0])且小于80(idxlist[1])时返回1……所以这实际上是一个插入到有序容器算法,只不过我们只需得到插入位置(索引),并不需要进行插入。


五、总结

  对于“一、基本代码”,其平均判断次数是 n/2,即 O(n)。
  对于“三、正确的优化”,其平均判断次数是 n-1,即 O(n)。运算复杂度与上一个一样,但是由于它避免了跳转,所以在项目较少时,该代码的效率最高。
  对于“四、全面优化”,由于它采用了二分法查找,其运算复杂度为 O(logn)。在项目很多时,它的效率最高。
 

原创粉丝点击