【恋上数据结构和算法】算法复杂度

1. 什么是算法

  • 算法是用于解决特定问题的一系列的执行步骤,比如以下代码。
/**
 * 计算 a 和 b 的和
 */
public static int plus(int a, int b) {
    return a + b;
}

/**
 * 计算 1 + 2 + 3 + ... + n
 */
public static int sum(int n) {
    int sum = 0;
    for (int i = 1; i <= n; i++) {
        sum += i;
    }
    return sum;
}
  • 使用不同算法,解决同一个问题,效率可能相差非常大。 比如下面的求和代码:
/**
 * 计算 1 + 2 + 3 + ... + n
  */
 public static int sum(int n) {
     int sum = 0;
     for (int i = 1; i <= n; i++) {
         sum += i;
     }
     return sum;
 }

 /**
  * 计算 1 + 2 + 3 + ... + n
  */
 public static int sum2(int n) {
   return (1 + n) * n / 2;
 }

2. 如何评判一个算法的好坏

  • 如果单从执行效率上进行评估,可能会想到这么一种方案

    • 比较不同算法对同一组输入的执行处理时间
    • 这种方案也叫做:事后统计法
  • 上述方案有比较明显的缺点

    • 执行时间严重依赖硬件以及运行时各种不确定的环境因素
    • 必须编写相应的测算代码
    • 测试数据的选择比较难保证公正性
  • 一般从以下维度来评估算法的优劣

    • 正确性、可读性、健壮性(对不合理输入的反应能力和处理能力)
    • 时间复杂度(time complexity):估算程序指令的执行次数(执行时间)
    • 空间复杂度(space complexity):估算所需占用的存储空间

3. 大O表示法(Big O)

  • 一般用大O表示法来描述复杂度,它表示的是数据规模 n 对应的复杂度
  • 忽略常数、系数、低阶
    • 9 >> O(1)
    • 2n + 3 >> O(n)
    • n2 + 2n + 6 >> O(n2)
    • 4n3 + 3n2 + 22n + 100 >> O(n3)
  • 注意:大O表示法仅仅是一种粗略的分析模型,是一种估算,能帮助我们短时间内了解一个算法的执行效率

4. 对数阶的细节

对数阶一般省略底数 log2n = log29 ∗ log9n,所以 log2n 、log9n 统称为 logn

5. 常见的复杂度

执行次数复杂度非正式术语
12O(1)常数阶
2n + 3O(n)线性阶
4n2 + 2n + 6O(n2)平方阶
4log2n + 25O(logn)对数阶
3n + 2nlog3n + 15O(nlogn)nlogn阶
4n3 + 3n2 + 22n + 100O(n3)立方阶
2nO(2n)指数阶
  • 复杂度大小:
    O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)

  • 可以使用函数生成工具对比复杂度的大小:
    复杂度对比工具

  • 规模数据较小时
    log(n),n,n*log(n),n2,n3,2^n

  • 数据规模较大时
    log(n),n,n*log(n),n2,n3,2^n

6. fib函数的时间复杂度分析

在这里插入图片描述

  • 1 + 2 + 4 + 8 = 20 + 21 + 22 + 23 = 24 − 1 = 2n−1 − 1 = 0.5 ∗ 2n − 1
  • 所以复杂度是 O(2n)

fib 算法比较:

/**
 * 复杂度 O(2^n) 
 */
public static int fib1(int n) {
    if (n <= 1) {
        return n;
    }
    return fib1(n - 2) + fib1(n - 1);
}

/**
 * 复杂度 O(n)  5
 */
public static int fib2(int n) {
    if (n <= 1) {
        return n;
    }
    int first = 0, second = 1;
    while (n-- > 1) {
        second += first;
        first = second - first;
    }
    return second;
}
  • 传统递归方式复杂度是 O(2n)
  • 改进后复杂度变为了O(n)

7. 算法的优化方向

  • 用尽量少的存储空间
  • 用尽量少的执行步骤(执行时间)
  • 根据情况,可以
    • 空间换时间
    • 时间换空间

8. 多个数据规模的情况

下述代码复杂度为 O(n + k)

/**
 * 时间复杂度 n + k
  */
 public static void test(int n, int k) {
     for (int i = 0; i < n; i++) {
         System.out.println("test_n" + i);
     }

     for (int i = 0; i < k; i++) {
         System.out.println("test_k" + i);
     }
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值