数据结构与算法学习之(一)时间复杂度和空间复杂度

<!-- index-menu -->

大 O 复杂度表示法

算法的执行效率,粗略地讲,就是算法代码执行的时间。大 O 时间复杂度实际上并不具体表示代码真正的执行时间,而是表示代码执行时间随数据规模增长的变化趋势,所以,也叫作渐进时间复杂度(asymptotic time complexity),简称时间复杂度。

时间复杂度分析

只关注循环执行次数最多的一段代码

大 O 这种复杂度表示方法只是表示一种变化趋势。忽略掉公式中的常量、低阶、系数,只需要记录一个最大阶的量级就可以了。所以只关注循环执行次数最多的那一段代码就可以了

几种常见时间复杂度分析

O(1)

O(1) 只是常量级时间复杂度的一种表示方法,并不是指只执行了一行代码。比如这段代码,即便有 3 行,它的时间复杂度也是 O(1),而不是 O(3)。

 int i = 8;

 int j = 6;

 int sum = i + j;

代码的执行时间不随 n 的增大而增长,这样代码的时间复杂度我们都记作 O(1)。

O(n)

 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 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;
 }

O(logn)、O(nlogn)

 i = 1;
 while (i <= n)  {
   i = i * 2;
 }

只要知道 x 值是多少,就知道这行代码执行的次数了。通过 2^x = n 求解 x ,x=log2n,所以,这段代码的时间复杂度就是 O(log2n)。

在对数阶时间复杂度的表示方法里,我们忽略对数的“底”,统一表示为 O(logn)。

如果一段代码的时间复杂度是 O(logn),循环执行 n 遍,时间复杂度就是 O(nlogn) 。

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; // O(m + n)
  // return sum_1 * sum_2; // O(m * n)
}

空间复杂度分析

空间复杂度全称就是渐进空间复杂度(asymptotic space complexity),表示算法的存储空间与数据规模之间的增长关系。

// 第 2 行代码中,我们申请了一个空间存储变量 i,但是它是常量阶的,跟数据规模 n 没关
// 系,所以我们可以忽略。第 3 行申请了一个大小为 n 的 int 类型数组,除此之外,剩下的代
// 码都没有占用更多的空间,所以整段代码的空间复杂度就是 O(n)。
void print(int n) {
  int i = 0;
  int[] a = new int[n];
  for (i; i <n; ++i) {
    a[i] = i * i;
  }

  for (i = n-1; i >= 0; --i) {
    print out a[i]
  }
}

常见的空间复杂度就是 O(1)、O(n)、O(n2 )。O(logn)、O(nlogn) 这样的对数阶复杂度基本都用不到。

最后修改:2020 年 07 月 13 日 06 : 48 PM