数据结构与算法、第二篇:复杂度分析(上)

事后统计法
1.测试结果非常依赖测试环境
2.测试结果受数据规模的影响很大
我们需要一个不用具体的测试数据来测试,就可以粗略的估计算法的执行效率的方法

一、什么是复杂度分析?

数据结构和算法解决是“如何让计算机更快时间、更省空间的解决问题”。因此需从执行时间和占用空间两个维度来评估数据结构和算法的性能。分别用时间复杂度和空间复杂度两个概念来描述性能问题,二者统称为复杂度。复杂度描述的是算法执行时间(或占用空间)与数据规模的增长关系。

二、为什么要进行复杂度分析?
  1. 和性能测试相比,复杂度分析有不依赖执行环境、成本低、效率高、易操作、指导性强的特点。
  2. 掌握复杂度分析,将能编写出性能更优的代码,有利于降低系统开发和维护成本。
三、如何进行复杂度分析---->大O表示法
  1. 来源
    算法的执行时间与每行代码的执行次数成正比,用T(n) = O(f(n))表示,其中T(n)表示算法执行总时间,f(n)表示每行代码执行总次数,而n往往表示数据的规模。
  2. 特点
    以时间复杂度为例,由于时间复杂度描述的是算法执行时间与数据规模的增长变化趋势,所以常量阶、低阶以及系数实际上对这种增长趋势不产决定性影响,所以在做时间复杂度分析时忽略这些项。

时间复杂度---->渐进时间复杂度,表示算法的执行时间与数据规模之间的增长关系
  1. 分析法则
    a. 单段代码看高频:比如循环。  
    b. 多段代码取最大:比如一段代码中有单循环和多重循环,那么取多重循环的复杂度。  (加法法则)
    c. 嵌套代码求乘积:比如递归、多重循环等  (乘法法则)
    d. 多个规模求加法:比如方法有两个参数控制两个循环的次数,那么这时就取二者复杂度相加。(加法法则特殊情况[两个规模的参数无法确定谁的量级大])  
  1. 复杂度量级
    1. 多项式阶:随着数据规模的增长,算法的执行时间和空间占用,按照多项式的比例增长。

      O(1)(常数阶)
      O(logn)(对数阶)
      O(n)(线性阶)
      O(nlogn)(线性对数阶)
      O(n^2)(平方阶)
      O(n^3)(立方阶)

    2. 非多项式阶:随着数据规模的增长,算法的执行时间和空间占用暴增,这类算法性能极差。

      O(2^n)(指数阶)
      O(n!)(阶乘阶)

  2. 常用的时间复杂度级别?

O(1)

 int i = 8;
 int j = 6;
 int sum = i + j;

只要代码的执行时间不随n的增大而增大,这样代码的时间复杂度我们都记作O(1)。或者说,一般情况下,只要算法中不存在循环语句,递归御酒,即便有成千上万行的代码,其时间复杂度也是O(1)

O(longn)\O(nlogn)

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

推理:因为第三行代码是循环执行次数最多的。所以,我们只要能计算出这行代码被执行了多少次,就能知道整段代码的时间复杂度
从代码中可以看出,变量i的值从1开始取,每循环一次就乘以2。当大于n时,循环结束。
实际上,变量i的取值就是一个等比数列。如果我把它一个一个列出来,就应该是这样
分析
所以,我们只要知道x值是多少,就知道这行代码执行的次数了。通过2^x = n求解x–>x = log2n

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

这段代码的时间复杂度为 O(log3n)。
因为对数之间是可以相互转换的,log3n就等于log32 * log2n,所以O(log3n) = O(C*log2n),其中C=log32是一个常量,基于我们前面的一个理论:在采用大O标记复杂度度的时候,可以忽略系数。因此在对数阶时间复杂度的表示方法里,我们忽略对数的底,统一表示为O(logn)
O(nlogn)---->如果一段代码的时间复杂度是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;
}

代码的复杂度由两个数据的规模来决定。这个时候我们无法评估m和n谁的量级大,所以我们再表示复杂度的时候,就不能简单的利用加法法则,省略掉其中一个,所以上面代码的时间复杂度就是O(m+n)
针对这种情况,我们需要把加法规则改为:T1(m) +T2(n) = O(f(m)+g(n))。但是乘法法则继续有效:T1(m)*T2(n)=O(f(m)*f(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]
  }
}

第3行申请了一个大小为n的int类型数组,除此之外,剩下的代码都没有占用更多的空间,所以整段代码的空间复杂度就是O(n)

常见的空间复杂度就是O(1) O(n) O(n^2)
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值