时间复杂度和空间复杂度
第一章并没有什么很难的内容,大部分都是一些比较晦涩的定义,多看看背背就行。唯一的重点就是算法的时间复杂度和空间复杂度这里。
对于比较算法的效率来说,最重要的两个指标就是时间复杂度和空间复杂度。其中用到时间复杂度的情况更多一点。
衡量算法效率主要有两种方法:事前估计法和事后统计法。一般来说,由于事后统计法缺陷太大,所以很少使用。在这里我们只考虑事前估计法。
时间复杂度
算法的执行时间主要以下面的几个因素来影响:
-
使用的算法的优赖。
-
问题的输入规模
-
机器执行指令的速度。
其中为解决问题选择更合适的算法比较考验自己的代码水平,我们不做更多的说明。问题的输入规模决定了程序执行时间的长短。为了方便计算问题的时间复杂度,我们不考虑机器的软硬件环境,将每条语句的执行时间定为一个单位时间。
语句频度之和
语句频度我们用f(n)表示。在书中给的那个例子中,我当时一直没想通的地方只有一点,可能大家也会有疑问。
for(i=1;i<=n;i++) //频度为n+1
for(j=1;j<=n:j++) //频度为n*(n+1)
{
c[i][j]=0; //频度为n**2
}
我当时一直在想为什么第一层循环那里会是n+1,而在第二层循环那里就成为了n*(n+1)。这里第一层循环按照定义会循环n次,但是这条语句会执行第n+1次,然后发现for语句不符合条件,然后结束。对于第二层循环来说,第一层循环只执行了n次,所以第二层是n*(n+1)次。
这本书中有很多晦涩难懂的定义,看的头疼。在我看来,计算时间复杂度就是找到整个程序中运行次数最多的基本语句就是这个程序的时间复杂度。一般来说时间复杂度看嵌套循环。一个循环乘一个n(如果n是循环次数的话)。但是,要注意一点,比如说循环是(for i=1;i<100;i++){cnt++},这样的语句时间复杂度还是O(1),因为语句频度还是个常数。
x = 0; y=0;
for(k=1;i<=n;k++)
x++;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
y++;
这个程序的的时间复杂度就是O(n**2)。
而有的程序循环语句比较复杂,比如说
x=1;
for(i=1;i<=n;i++)
for(j=1;j<=i;j++)
for(k=1;k<=j;k++)
x++;
像这种的程序,循环次数比较复杂的。我们可以计算这个语句x++运行的次数。书中也给出了求和方法,然后选择最高次幂,忽略最高次幂的系数就是这个程序的时间复杂度O(n**3)。
一般来说,常见的时间复杂度有常数阶O(1),对数阶O(log2n),线性阶O(n),平方阶O(n**2)等等。
最好,最坏和平均时间复杂度
最好情况下的时间复杂度为最好时间复杂度,最坏情况下的时间复杂度为最坏时间复杂度,算法的平均是指算法在所有的可能情况下,按照输入实例以等概率出现时,算法计算量的加权平均值。
算法的空间复杂度
我们采用渐进空间复杂度作为算法所需储存空间的量度,简称空间复杂度。记作:
S(n) = O(f(n))
一般来说我们只需要计算算法实现所需要的辅助空间就行。下面的程序是一个将一维数组的n个数逆序存放的程序。
for(i=0;i<=n;i++)
{
t=a[i];
a[i]=a[n-i-1];
a[n-i-1]= t;
}
这个算法的实现只需要一个变量t的空间就可以实现程序功能,所以这个空间复杂度为O(1)。
for(i=0;i<=n;i++)
{
b[i]=a[n-i-1];
}
for(i=0;i<=n;i++)
{
a[i]=b[i];
}
这个程序就使用了一个和a数组一样大的b数组,所以空间复杂度为O(n)。
个人公众号:岚岚散散。