zoukankan      html  css  js  c++  java
  • 算法概述和时间复杂度

    什么是算法

    算法是用于解决特定问题的一系列的执行步骤,使用不同算法,解决同一个问题,效率可能相差非常大

    比如:求第 n 个斐波那契数(fibonacci number)

    /**
         * 斐波那契数列 Fibonacci sequence
         * 斐波那契数列(Fibonacci sequence),又称黄金分割数列、
         * 因数学家莱昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,
         * 指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……
         * 在数学上,斐波那契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)
         */
        public static int fibonacciSequence_01(int i){
            if(i<=1){
                return i;
            }
            return fibonacciSequence_01(i-1)+fibonacciSequence_01(i-2);
        }
    
        public static int fibonacciSequence_02(int n){
            if(n<=1){
                return n;
            }
            int first=0;
            int second=1;
            for (int i=0;i<n-1;i++){
                int sum=first+second;
                first=second;
                second=sum;
            }
            return second;
        }

    如何评判一个算法的好坏?

    如果单从执行效率上进行评估,可能会想到这么一种方案 : 比较不同算法对同一组输入的执行处理时间 .这种方案也叫做:事后统计法

    此方案有比较明显的缺点 1.执行时间严重依赖硬件以及运行时各种不确定的环境因素 2.必须编写相应的测算代码 3.测试数据的选择比较难保证公正性

    还可以从以下维度来评估算法的优劣

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

    大O表示法(Big O)

    一般用大O表示法来描述复杂度,它表示的是数据规模 n 对应的复杂度,此方法忽略常数、系数、和低阶

    ◼ 注意:大O表示法仅仅是一种粗略的分析模型,是一种估算,能帮助我们短时间内了解一个算法的执行效率

    对数阶的细节

    log2n = log29 ∗ log9n 

    所以 log2n 、log9n 统称为 logn

    常见的复杂度

    下图来自维基百科

    常数级别O(1)

    O(1):算法复杂度和问题规模无关。换句话说,哪怕你拿出几个PB的数据,我也能一步到位找到答案。

    理论上哈希表就是O(1)。因为哈希表是通过哈希函数来映射的,所以拿到一个关键字,用哈希函数转换一下,就可以直接从表中取出对应的值。和现存数据有多少毫无关系,故而每次执行该操作只需要恒定的时间

    (当然,实际操作中存在冲突和冲突解决的机制,不能保证每次取值的时间是完全一样的)

    对数级别O(logN)

     O(logN):算法复杂度和问题规模是对数关系。换句话说,数据量大幅增加时,消耗时间/空间只有少量增加(比如,当数据量从2增加到2^64时,消耗时间/空间只增加64倍,常见于二分法

    int number = 1; // 语句执行一次
    while (number < n) { // 语句执行logn次
      // 这里的2是log的底数
      // 底数在大O符号中是省去的
      number *= 2; // 语句执行logn次
    }

    线性级别O(N)

    O(n):算法复杂度和问题规模是线性关系。换句话说,随着样本数量的增加,复杂度也随之线性增加

    int i =0; // 语句执行一次
    while (i < n) { // 语句执行n次
      print(i); //语句执行n次
      i++; // 语句执行n次
    }

    线性对数级别O(NlogN)

    public static void test6(int n) {
            // log5(n)
            // O(logn)
            while ((n = n / 5) > 0) {
                System.out.println("test");
            }
        }

    平方级别O(N^2)

     O(n^2)计算的复杂度随着样本个数的平方数增长。这个例子在算法里面,就是那一群比较挫的排序,比如冒泡等等

    for (int i = 0; i < n; i++) { // 语句执行n次
      for (int j = 0; j < n; j++) { // 语句执行n^2次
         print('I am here!'); // 语句执行n^2
      }
    }

    指数级别O(2^N)

    如果一个算法的运行时间是指数级的(exponential),一般它很难在实践中使用

    斐波那契数的例子的第一个算法就是O(2^N)

     有时候算法之间的差距,往往比硬件方面的差距还要大

    算法的优化方向

    1.用尽量少的存储空间 

    2.用尽量少的执行步骤(执行时间) 

    3.根据情况,可以 

    • 空间换时间 
    • 时间换空间
  • 相关阅读:
    C 标准库
    C 标准库
    C 标准库
    C 标准库
    Chrome内核保存为mhtml(单网页)
    C 标准库
    C 标准库
    【转】AOP
    [转]控制反转与依赖注入模式
    [转]乐观锁、悲观锁、死锁的区别
  • 原文地址:https://www.cnblogs.com/lusaisai/p/13663904.html
Copyright © 2011-2022 走看看