算法分析处于下面这个阶段:
把一个算法(指令的集合)给一个程序,然后我们要考虑的就是这个算法所要的时间和空间,确定和分析算法需要的时间和空间的这个过程就是算法分析;
所以我们说程序运行的时间和空间开销实际上是指该程序的某个算法的时间和空间开销;
一个算法的运行时间实际上是输入规模的函数;
注意:运行时间除了和程序的质量有关之外还和机器的配置有关,所以当你要模拟一个函数来描述某个算法的运行时间与输入规模的关系时,一定要给定一台机器;
我们在衡量一个算法的时间函数的时候看的是dominant term,也就是说我们通常关心的是函数表达式中起到关键作用的那一项而不是所有项;因为其他非dominant term项只会在输入规模非常小的情况下起作用,当输入规模增大时,他们的效果就微乎其微了;
LogN 比平方和立方都来得慢一点;慢指的就是变化的速率;
在算法分析中,F(N)
1, 输入规模足够大以后,有效果的仅仅是dominant term
2, 机器不同,所以对应于某个输入规模值的时间值在不同机器上是不可比较的,但是变化速率在不同机器上却是可以互相比较的;
3, N非常小的时候的情况是不重要的;所以如果一个程序的输入规模本来就不大,那好的做法是选取最简单,最容易实现的算法而不是时间开销小的,因为这个时候时间开销总是在机器配置可以接受的范围里;
Big-Oh是用来提取dominant term并且表示函数的增长速率的;哦,终于明白了,比如对于插入排序,它的Big-Oh是O(N2),我还以为是指当输入规模为10的时候,应该运算100次呢,但是结果发现总是运算45次左右;而另一个假设是当输入规模是100的时候,应该运算10000次呢,但是结果发现总是运算4500次左右;这让本人百思不得其解,现在终于发现,这个Big-Oh并不是用来计算在特定的输入规模值下相应的函数开销的,而是计算随着输入规模的增长,时间开销函数值的增长速率;所以正确应用Big-Oh的做法是:首先必须输入一个规模值,来得到一个时间开销值,然后可以把这个规模值放大到你期望的值,那么时间开销值就是规模值放大倍数和Big-Oh表达的增长速率的结合;
输入规模小的时候对各个算法函数进行比较是不明智的,因为当N<50的时候,N+2500是大于N2,所以我们会误以为线性没有平方好;
最大连续子串问题:当子串的所有元素都是负数的时候,我们说最大连续子串的值是0,子串空子串;而不是说最大连续子串的值是所有负数中最大的那个,子串就是那个最大的负数组成的串。这样做是有原因的:空子串是任何一个串的子串,就好像空集是任何一个集合的子集一样;而空子串的值又是0,所以负数不会成为最大连续子串的值的;
How do we remove a loop?很简单,二次算法就是你想的那个算法,非常easy,二次算法既高效,思路又简单;线性算法虽然高效,但是思路就非常不清楚了,所以如果输入规模并不大,或者机器配置非常高的时候,那就不必考虑线性算法了;
Get rid of another loop is not so easy! 但是我们发现,二次算法实际上也是一个无遗漏的扫描算法,而三次算法不但是个无遗漏的扫描算法,而且做了大量的重复计算;所以,我们觉得,要创造出一个非无遗漏的,预测的算法出来是有可能的;
线性算法的优化理由是:
1, 如果Ai,j是一个子串并且它的串值Si,j<0,则如果q>j,那么Ai,q不可能是最大连续
子串;
2, 对于任意的i,如果Ai,j是一个子串,并且Si,j<0,那么,对于任意的i<=p<=j并且
p<=q,Ap,q要么不是一个最大子串,要么等于已经存在的一个最大子串Ai,q
/*最大连续子串问题--线性次方解决办法*/
public static int maxSubsequenceSum1(int[] a)
{
int maxSum=0,cout=0,seqStart=0,seqEnd=0;
int thisSum=0;
for(int i=0,j=0;j
{
thisSum+=a[j];
if(maxSum
{
maxSum=thisSum;
seqStart=i;
seqEnd=j;
}
else if(thisSum<0)
{
i=j+1;
thisSum=0;
}
}
return maxSum;
}
/*最大连续子串问题--二次方解决办法*/
public static int maxSubsequenceSum2(int[] a)
{
int maxSum=0,cout=0,seqStart=0,seqEnd=0;
for(int i=0;i
{
int thisSum=0;
for(int j=i;j
{
thisSum+=a[j];
if(maxSum
{
maxSum=thisSum;
seqStart=i;
seqEnd=j;
}
}
}
return maxSum;
}
/*最大连续子串问题--三次方解决办法*/
public static int maxSubsequenceSum3(int[] a)
{
int maxSum=0,cout=0,seqStart=0,seqEnd=0;
for(int i=0;i
for(int j=i;j
{
int thisSum=0;
for(int k=i;k<=j;k++,cout++)
{
thisSum+=a[k];
}
if(thisSum>maxSum)
{
maxSum=thisSum;
seqStart=i;
seqEnd=j;
}
}
return maxSum;
}
General Big-Oh 规则:
O(F(N)):Big-Oh is similar to less than or equal to,when growth rates are being considered.
比如,O(N2)的意思就是:该算法的运行时间随输入规模N增长的速率不会超过N2随着输入规模N的增长速率;
Ω(F(N)):Big-Omerga is similar to greater than or equal to,when growth rates are being considered.
比如,Big-Omerga(N2)的意思就是:该算法的运行时间随输入规模N增长的速率不会低于N2随着输入规模N的增长速率;
⊙(F(N)):Big-Theta is similar to euqal to,when growth rates are being considered.
o(F(N)): Little-Oh is similar to less than,when growth rates are being considered.
在使用Big-Oh的时候有以下两个原则:
1, 不要在F(N)中包括常数和低阶项,比如T(N)=O(2N2)和T(N)=O(N2+N)都应该
说成T(N)=O(N2)
2, 在要求Big-Oh分析的过程中,可以也应该抛弃所有leading constants和
relational Symbols
这里的四个规则评价的方式都是:该算法耗时的范围
而有另一个方式是:该算法平均耗时是多少;
注意:Big-Oh规则用来指示运行时间随输入规模N增大的速率的理论是建立在:输入规模足够大,大到中等规模;在小规模输入下,看不出Big-Oh指示的关系;
对于O(NlogN)来说,当N足够大的时候,它所指示的增长速率和O(N)是一样的;
Java中的数字数据类型都是有符号的,似乎没有无符号一说;
静态搜索问题:
定义:Given an integer X and an array A,return the position of X in A or an indication that
It is not present.If X occurs more than once,return any occurrence.The array A is never altered.
静态搜索的效率取决于array A是否已经被排序了;
1, 连续搜索:适合没有排序的数组,我们从下面三个方面来评价复杂度
首先是失败搜索的时间复杂度;
再次是最坏情况成功搜索的时间复杂度;
最后是平均的成功搜索的时间复杂度;
2, 二分搜索:
很明显,二分搜索的Big-Oh规则是O(LogN)的;
我们的目的是使得我们能够根据输入规模的大小来确定到底是使用哪种搜索算法,而不是告诉你哪种算法是绝对好的;当输入规模小于6的时候,如果你还用二分搜索那简直是愚蠢的做法;
3, Interpolation Search
内插搜索有两个限制:
1, 数组必须是在disk上而不是memory
2, 数据不止要被排序,而且要均等分配;
更重要的是,内插搜索在最糟情况下的时间消耗是非常不理想的;
最后需要说明的是:Big-Oh规则是有限制的,它忽略的常数和低阶项有时候会起到作用;它的估价一直建立在这样的信念上---内存是无穷大的;它在输入规模足够小的时候会给人们错误的指示;
|
Algorithm Analysis using java(学习笔记)
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/7178747/viewspace-160945/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/7178747/viewspace-160945/