认识时间复杂度

  时间复杂度就是用来评价算法流程的标准,你可以随意脑补一个算法,它的正确性保证了后,你怎么去评价整个流程的好坏?就是用时间复杂度来评价的。介绍时间复杂度之前,我们先解释一下常数时间的操作,

常数时间的操作:一个操作如果和数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作。

  比如,数组寻址操作、加减乘除操作、位运算操作,这些是和样本的数据量无关,你每次完成这些操作都是固定时间。比如说机器每个数有多少位(long类型64位,int类型32位),做加减乘除肯定是固定时间,再比如数组的寻址,在计算机里面就是内存跳一下。这些东西都是常数操作。

  那么时间复杂度到底是什么?我们先看它的概念:

时间复杂度为一个算法流程中,常数操作数量的指标。常用O(读作big O)来表示。具体来说,在常数操作数量的表达式中,只要高阶项,不要低阶项,也不要高阶项的系数,剩下的部分如果记为f(N),那么时间复杂度为O(f(N))。

  理解“只要高阶项,不要低阶项,也不要高阶项的系数”:

  有一个长度为n的无序数组,我们要将它排好序,设计的一种排序方式为:在0到n-1里遍历一次,找到min,然后放到0位置上;然后在1到n-1遍历一次,找到min放到1位置上....依次下去,直到把数组排好。

  这个复杂度怎么估计?第一次找到min时,过的是n个数,第二次找到min过的是n-1个数......最后排好需要过(n+n-1+n-2+...+2+1)个数,可以看出,这里常数操作数量的表达式是一个等差数列(n+1)n/2,可以写成:an²+bn+c。
  根据“只要高阶项,不要低阶项,也不要高阶项的系数”,这个时间复杂度就是O(n²)。

  评价一个算法流程的好坏,先看时间复杂度的指标,然后再分析不同数据样本下的实际运行时间,也就是常数项时间。

 

  下面通过一个简单的例子来理解时间复杂度:

  一个有序数组A,另一个无序数组B,请打印B中的所有不在A中的数,A数组长度为N,B数组长度为M。

  【算法流程1】:对于数组B中的每一个数,都在A中通过遍历的方式找一下;

for(int i=0;i<M-1;i++){
    for(int j=0;j<N-1;j++){
      ...
  }      
}

  任何一个M中的每一个数都要遍历N次,所以整体常数操作的表达式为f(M,N) = M * N,所以时间复杂度为O(M*N)

  【算法流程2】:对于数组B中的每一个数,都在A中通过二分的方式找一下;

  B中一共有M个数,每找一个数都通过二分的方式,二分查找常数操作量约为logN,因此B中每一个数确定在A中是否存在的代价为O(logN),所以时间复杂度为O(M*logN)

  【算法流程3】:先把数组B排序,然后用类似外排的方式打印所有不在A中出现的数;

  思路:

  

  第一步:数组B排序的代价为:O(M*logM),

  第二步:类似外排的方式,a最多指N个数,b最多指M个数,当a和b有一个到达终点,整个流程就结束,最差的情况就是a指N个数,b指M个数。所以复杂度为O(N+M)

  由于样本量不确定,所以此处的复杂度为O(M*logM)+O(N+M)。如果N很小,复杂度为O(M*logM);如果M很小,复杂度就变为O(N+M)了。 

  【结论】

  综合上述3个算法,可以看出算法1是最差的。如果A数组很短,B数组很长,算法2更好;反之,算法3更好。

 

posted @ 2019-05-25 14:41  yi0123  阅读(398)  评论(0编辑  收藏  举报