如何提高程序的效率(一)
――设计优秀的算法
(From Programming Peals by Jon Bentley)
一个简单的问题,往往有许多不同的解决方案,那么如何找到一个相比之下比较好(事实上很难找到绝对好的方法)的方案呢?我们需要一个优秀的算法,优秀的算法能够给很大程度上提高程序的效率。
问题描述:问题的输入是具有n个整数的向量x ,输出是输入向量的任何连续子向量中的最大和。例如,如果输入向量包含下面10个元素:
31 , -41 , 59 , 26 , -53 , 58 , 97 , -93 , -23 , 84
当所有的输入都是正数的时候,问题很容易解决,此时最大的子向量就是整个输入向量。
但是,如果出现负数该怎么办,这就是我们下面所研究的几个算法所讨论的内容。
一个简单平方算法(O(n2)):
int maxsofar=0;
for(int i=0;i<n;i++)
{
sum=0 ;
for(int j=I;j<n;j++)
{
sum+=x[j];
maxsofar= max( maxsofar,sum );
}
}
一个分治算法(O(log n)):
分治原理:
要解决规模为n的问题,可递归地解决两个规模近似为n/2 的子问题,然后对他们的答案进行合并以得到整个问题的答案。
程序略
一个现在看来最高效的程序——scan 算法(O(n)):
下面给出此程序的C++完整代码:
#include <iostream.h>
//#include <stdlib.h>
int max(int a,int b)
{
return a>b?a:b;
}
int scan(int a[],int n)
{
int maxsofar,maxendinghere;
maxsofar=maxendinghere=0;
for(int i=0;i<n;i++)
{
maxendinghere=max(maxendinghere+a[i],0);
maxsofar=max(maxsofar,maxendinghere);
}
return maxsofar;
}
void main()
{
int a[10]={-6,-8,-89,7,3,8,-79,45,8,-5};
cout<<scan(a,10)<<endl;
}
可以看出scan 算法是一个接近完美的算法,因为解决这个问题少于O(n)是不可能的。