常见的时间复杂度和复杂度如何分析

算法和数据结构是相辅相成的,数据结构是为算法服务的,算法要作用在特定的数据结构上

一.如何分析时间复杂度

大O复杂度表示法:它并不具体表示代码真正的执行时间,而是表示代码执行时间随数据规模增长的变化趋势。
也叫作'渐进时间复杂度',简称时间复杂度。表示算法的执行时间与数据规模之间的增长关系
**时间复杂度分析方式:**
1.只关注循环执行次数最多的一段代码
如下
 int cal(int n) {
   int sum = 0;
   int i = 1;
   for (; i <= n; ++i) {
     sum = sum + i;
   }
   return sum;
 }
 这段代码总的时间复杂度就是 O(n)
2.加法法则:总复杂度等于量级最大的那段代码的复杂度
int cal(int n) {
   int sum_1 = 0;
   int p = 1;
   for (; p < 100; ++p) {
     sum_1 = sum_1 + p;
   }

   int sum_2 = 0;
   int q = 1;
   for (; q < n; ++q) {
     sum_2 = sum_2 + q;
   }
 
   int sum_3 = 0;
   int i = 1;
   int j = 1;
   for (; i <= n; ++i) {
     j = 1; 
     for (; j <= n; ++j) {
       sum_3 = sum_3 +  i * j;
     }
   }
 
   return sum_1 + sum_2 + sum_3;
 }
 
这个代码分为三部分,分别是求 sum_1、sum_2、sum_3。
我们可以分别分析每一部分的时间复杂度,然后把它们放到一块儿,再取一个量级最大的作为整段代码的复杂度。

第一段因为循环是一个已知数。所有照样是常量级的执行时间。
那第二段代码和第三段代码的时间复杂度分别是 O(n)O(n*n),所以,整段代码的时间复杂度就为 O(n*n)。
也就是说:总的时间复杂度就等于量级最大的那段代码的时间复杂度
3. 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积

int cal(int n) {
   int ret = 0; 
   int i = 1;
   for (; i < n; ++i) {
     ret = ret + f(i);
   } 
 } 
 
 int f(int n) {
  int sum = 0;
  int i = 1;
  for (; i < n; ++i) {
    sum = sum + i;
  } 
  return sum;
 }
整个 cal() 函数的时间复杂度是,T(n) = T1(n) * T2(n) = O(n*n) 

二、几种常见时间复杂度实例分析

主要是几种多项式时间复杂度
1.O(1):代码如下
 int i = 8;
 int j = 6;
 int sum = i + j;
 一般情况下,只要算法中不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是Ο(1)
2.O(logn)O(nlogn)
对数阶时间复杂度非常常见,同时也是最难分析的一种时间复杂度。例子如下:
 i=1;
 while (i <= n)  {
   i = i * 2;
 }
根据复杂度分析方法,第三行代码是循环执行次数最多的。
所以,只要能计算出这行代码被执行了多少次,就能知道整段代码的时间复杂度。

从代码中可以看出,变量 i 的值从 1 开始取,每循环一次就乘以2。当大于 n 时,循环结束。
实际上,变量 i 的取值就是一个等比数列。如果我把它一个一个列出来,就应该是这个样子的:

在这里插入图片描述

所以,我们只要知道 x 值是多少,就知道这行代码执行的次数了。通过 2x=n 求解 x,x=log2n
所以,这段代码的时间复杂度就是 O(log2n)
这段代码的时间复杂度是多少?
 i=1;
 while (i <= n)  {
   i = i * 3;
 }
根据上面的分析思路,这段代码的时间复杂度为 O(log3n)。
总结:不管是以 2 为底、以 3 为底,可以把所有对数阶的时间复杂度都记为 O(logn)。
因为O(log3n) = O(C * log2n)可以互相转换。
而在采用大 O 标记复杂度的时候,可以忽略系数,即 O(Cf(n)) = O(f(n))。

注:归并排序、快速排序的时间复杂度都是 O(nlogn)
3. O(m+n)O(m*n):如下,代码的复杂度由两个数据的规模来决定
int cal(int m, int n) {
  int sum_1 = 0;
  int i = 1;
  for (; i < m; ++i) {
    sum_1 = sum_1 + i;
  }

  int sum_2 = 0;
  int j = 1;
  for (; j < n; ++j) {
    sum_2 = sum_2 + j;
  }

  return sum_1 + sum_2;
}
从代码中可以看出,m 和 n 是表示两个数据规模。
我们无法事先评估 m 和 n 谁的量级大,所以,上面代码的时间复杂度就是 O(m+n)

三、空间复杂度

'空间复杂度全称就是渐进空间复杂度,表示算法的存储空间与数据规模之间的增长关系。'
常见的空间复杂度就是 O(1)O(n)O(n*n).

四、最好、最坏、平均、均摊时间复杂度

1.最好情况时间复杂度就是,在最理想的情况下,执行这段代码的时间复杂度。
2.最坏情况时间复杂度就是,在最糟糕的情况下,执行这段代码的时间复杂度
3.平均情况时间复杂度:全称加加权平均时间复杂度或者期望时间复杂度。
4.均摊时间复杂度:均摊时间复杂度就是一种特殊的平均时间复杂度,在能够应用均摊时间复杂度分析的场合,一般均摊时间复杂度就等于最好情况时间复杂度。

你可能感兴趣的:(Java基础,数据结构,算法,java)