《程序员实用算法》试读:1.2.2主要的优化:函数调用
另一种常见的算法技术是消除递归。递归是使函数调用它自身的行为。在C语言中,所有的函数都可以进行递归调用:即它们都能调用自身,至少在理论上如此。实际上,像main()和exit()这样的函数在进行递归调用时可能会引发问题。不过,几乎所有不会终止程序的函数都可以调用它们自身。在算法中经常会使用递归技术,因为它可以产生短小、优雅的解决方案。不过,它的代价高昂,包括时间和系统资源两方面,尤其体现在栈空间的消耗上。第5章给出了关于如何消除递归的一些示例。在可能的情况下,应尽量避免使用递归。
在MSDOS环境下,还有另外几种技术可用于减少函数调用的开销。首先,启用某些高级编译器提供的优化功能,它们允许使用寄存器而不是栈来传递函数参数(例如:Borland使用pr开关,Microsoft使用/Gr开关以及fastcall关键字,而Watcom则会默认执行优化)。如果用到了第三方程序库,在使用这些功能时就应该小心谨慎;有关更多信息,请参考相关的编译器文档。
MSDOS用户的第二个选择是使用pascal关键字。它将影响被调用的函数如何操作栈。如果使用这个关键字,可以同时节省时间和空间。与上述的编译开关一样,也必须小心使用pascal关键字。它不能用于参数数量可变的函数,并且一般不能把它与上述的编译开关结合起来使用。同样,请认真阅读编译器文档。如果必须从这两种方法中选择一种,就必须检查你的程序。如果程序通常只传递数量很少的参数(但不是零个参数),就使用第一个选项;如果程序具有多种类型的函数,有的函数不带参数,有的函数则带有两个或三个以上的参数,那么pascal选项将更高效。
最后,认真学习算法,然后钻研其中最频繁使用的部分。在这个过程中,拥有一种优秀的性能测量和跟踪工具(profiler)将给你带来巨大的好处。购买一种这样的工具并使用它;通过定期使用它可以加快代码的执行速度。在后面的各章中,在演示算法时我们强调了代码的清晰性。如果由于进行优化而使代码含义晦涩,我们将放弃这样做。只要有可能,我们就会给出关于在什么地方可以优化算法的提示和信息。