您的位置:首页 > 其它

一个模式匹配算法的优化

2011-10-10 15:43 260 查看
看《编程珠玑》第8章,里面一章介绍了针对一个模式匹配问题算法的优化策略,由于优化后算法与原始算法效率上的大幅度增强,我被震惊了。

问题:

在一个向量中寻找最大子向量。

书上有伪代码,我还是实现了一下。

原始算法,一个3重循环

int alg1(int* x,int count)
{
int maxsofar = 0;
for(int i=0;i<count;i++)
{
for (int j=i;j<count;j++)
{
int sum = 0;
for (int k=i;k<j;k++)
{
sum +=x[k];
}
maxsofar = max(maxsofar,sum);
}
}
return maxsofar;
}
简单改进,最内重循环浪费了先前的加法结果,于是3阶循环可以优化到2阶:
int alg2(int* x,int count)
{
int maxsofar = 0;
for(int i=0;i<count;i++)
{
int sum = 0;
for (int j=i;j<count;j++)
{
sum += x[j];
maxsofar = max(maxsofar,sum);
}
}
return maxsofar;
}
此算法同样是2阶,不过它先开辟内存空间计算了和,数组的[-1]位置的值先保存了一下,算完后还原,书上说不保存也没问题,我一试直接堆栈出错了。
int alg2b(int* x,int count)
{
int cumarr[MAXNUM];
int hold  = cumarr[-1];
cumarr[-1] = 0;
for(int i=0;i<count;i++)
cumarr[i] = cumarr[i-1] + x[i];
int maxsofar = 0;
int sum;
for (int i=0;i<count;i++)
{
for (int j=i;j<count;j++)
{
sum = cumarr[j] - cumarr[i-1];
maxsofar = max(maxsofar, sum);
}
}
cumarr[-1] = hold;
return maxsofar;
}
接着优化。

接下来是分治思想的运用,分治无疑是将一个大问题分成一些小问题,这里首先将整个数组分成2个小数组,于是最大子数组要么在前一个中,要么在后一个中,要么就是跨越了这2个数组,在它们中间。如果是跨越的,那么这个最大子数组就围绕在前后数组分界数位置,可以从这个分界数开始向前获得最大子数组,向后获得最大子数组,其和便是跨越的最大子数组了。分治由于是2分,其效率为O(nlogn)

int alg3(int* x,int count,int l,int u)
{
int lmax,rmax,sum,m;
if(l > u) return 0;
if(l == u) return max(0,x[l]);
m = (l+u)/2;
lmax = sum = 0;
for (int i=m;i>=l;i--)
{
sum += x[i];
lmax = max(lmax,sum);
}
rmax = sum = 0;
for (int i=m+1;i<=u;i++)
{
sum += x[i];
rmax = max(rmax,sum);
}
return max(lmax+rmax, max(alg3(x,count,l,m), alg3(x,count,m+1,u)));
}
最后是一个NB之极的扫描算法,只有一阶!原理:前i个元素中,最大总和子数组要么在前i-1个元素中(我们将其存储在maxsofar中),要么其结束位置为i(我们将其存储在maxendinghere中)。代码很精辟,我觉得即使知道了原理也不一定写得出这样的代码。
int alg4(int* x, int count)
{
int maxsofar = 0;
int maxendinghere = 0;
for (int i=0;i<count;i++)
{
maxendinghere = max(maxendinghere+x[i],0);
maxsofar = max(maxsofar,maxendinghere);
}
return maxsofar;
}
最后是结果:count = 10000,这个量级,算法1需要好几分钟,我都懒得让它算了。

这个让程序生成一个随机数组,并且由于种子固定,每次运行程序,这个随机数组是固定的。

int x[MAXNUM];
srand(1);//array is same when running the program everytime
for(int i=0;i<MAXNUM;i++)
x[i] = rand()%100-50;


alg2 result: 5264 | time cost: 2.839s

alg2b result: 5264 | time cost: 2.791s

alg3 result: 5264 | time cost: 0.011s

alg4 result: 5264 | time cost: 0.001s

那0.001也夸大了,实际在毫秒数量级之下。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: