如何评定一个算法的优劣?

231 阅读2分钟

评定一个算法的优劣指标: 1、正确性,可读性,容错性。 2、复杂度。 本文主要介绍复杂度内容。
研究学习算法的目的就是让程序:运行速度快,节省内存等资源消耗。


复杂度

  • (快)时间复杂度: 估算程序执行指令的次数。(执行时间)
  • (省)空间复杂度:估算程序运行需要的存储空间。

时间复杂度

分析方法有两种

  • 事后统计法 用测试程序和数据来运行已编写好的算法,对其执行时间进行比较。
  • 事前统计法 不依赖具体的测试程序和数据,根据统计方法对算法执行效率进行分析的方法。 事后统计法存在各种缺陷,暂不介绍。想了解,找度娘。 事前统计法的计算逻辑是怎么计算的呢?
    首先:假设每个代码语句每执行一次的耗时是一样的,记为T
    例如:
public void sum(int n) {
    int sum = 0; // 执行1次
    for(int i = 0; i < n; i++) { // i=0;执行1次; i < n 循环执行n次 ; i++  循环执行n次
        int base = i; // 循环执行n次
    }
}

上面这段代码的时间复杂度为:(1+(1+2n)+n)*T = (2+3n)*T 列举时间复杂度的计算:

// 时间复杂度为 1
public void sum(int n) {
    if (n % 2 == 0){
        System.out.println("偶数");
    }else {
        System.out.println("奇数");
    }
}
// 时间复杂度为 log2(n)
public void sum(int n) {
    if ((n = n / 2) > 0){
        System.out.println("end");
    } 
}

计算斐波那契数列的两种方式 ”递归和滚动变量“复杂度对比

// 斐波那契数列:1 1 2 3 5 8 ....n    计算公式: f(n) = f(n-1)+f(n-2)
//*** 递归 时间复杂度估算为 2^n =>O(2^n)
public static long fbiA(int n) {
    if(n>0 && n <= 2) return 1;
    return fbiA(n-1) + fbiA(n-2);
}
// *** 滚动变量 2 + 1+(n-2)*5 = 5n -7=>O(n)
public static long fbiB(int n) {
    if(n>0 && n <= 2) return 1;
    long a = 1;
    long b = 1;
    for(int i = 2;i< n;i++) {
        long sum = a+b;
        a = b;
        b = sum;
    }
    return b;
}

因为每行代码的执行时间T可以忽略不记。
所以时间复杂度与每行代码的执行次数n成正比。
由于时间复杂度为估算值,但是像这种的(log2(n)、n!、1、5n-7)描述方式太过于繁琐。 所以将所有代码的执行总时间T(n)和每行代码的执行次数n之间的关系表示:
T(n)=O(f(n))
公式中的O表示代码的执行总时间T(n)和其执行总次数f(n)成正比。这种表示法,称之为大O记法

大O记法的原则

  • 忽略常数、系数、低阶
原表示大O表示法说明
9O(1)无论9 还是10000都为O(1)
2n+1O(n)
n+1O(n)
n^2+2n+1O(n^2)
n^2+n^2+2n+1O(n^3)
log2(n)log(n)

image.png

空间复杂度

算法的空间复杂度通过计算算法所需的存储空间实现,算法空间复杂度的计算公式记作:S(n)=O(f(n)),其中n为问题的规模,f(n)为语句关于n所占存储空间的函数。

在平时的开发中更多的是用空间换时间,关于算法的空间复杂度就介绍到这里。