数据结构与算法 02 时间复杂度分析 → 事前后分析估算法&&执行代码次数

2.1 算法的时间复杂度分析


  • 我们要计算算法时间耗费的情况,首先我们得度量算法的执行时间,那么如何度量呢?

分析估算方法:


    比较容易想到的方法就是我们把算法执行若干次,然后拿个计时器在旁边计时,但这是非常荒谬的。因为现如今的计算机计算速度,已经无法用肉眼来进行观测。那么怎么办呢?我们可以 让计算机 自己来监测自己!
利用 计算机计时器对不同的算法编制的程序进行运行时间的计算。从而确定算法效率的高低。但是这种方法也有很大的缺陷:那就是必须一局算法实现编制好的测试程序,通常要花费大量时间和精力,测试完了如果发现测试的是非常糟糕的算法,那么之前所做的事情就属于无用功了,并且不同的测试环境(硬件环境)也会出现些许差别,甚至测试后的运行时间差异很大!你家电脑配置好,可能就非常快,配置不好就可能贼慢。(这个太主观了,不客观!)

  • 运行时间 测试程序
public class 运行时间计算 {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        int sum = 0;
        int n = 100;
        for(int i = 1;i <= n;++i)
        {
            sum+= i;
        }
        System.out.println(sum);

        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}

这种方法 是非常简单的,但不适合我们 算法工程师 去直接使用。
在这里插入图片描述
太快了,看到没 ? 根本 测试不出来。。(这叫做 “事后分析估算法”


2.1.1 事前分析估算法

在计算机程序编写前,依据统计方法对算法进行估算,经过总结。我们发现一个高级语言编写的程序在计算机上运行所消耗的时间完全取决于 下列因素:

  1. 算法采用的策略和方案;
  2. 编译产生的代码质量;(无法控制,由使用的编程语言决定
  3. 问题的输入规模(所谓的问题输入规模就是输入量的多少);
  4. 机器执行指令的速度;

所以我们如果 把上述中的 计算机硬件、软件 等有关因素,排除在外。那么就仅仅 剩下 输入规模和策略方案 会影响到 算法的效率了。这回我们再进行分析。


需求:从 1 ~ 100 的总和

  • 第一种解法:
//如果输入量 n 为 1,则需要计算 1 次;
//如果输入量 n 为1亿,则需要计算1一次;
//当你只考虑 输入规模和策略方案的时候,你就会发现我们所谓的效率,就可以用执行 多少次代码 来衡量!!
public class 执行代码次数 {
    public static void main(String[] args) {
        int sum = 0;//执行1次
        int n = 100;//执行1次
        for(int i = 1;i<=n;++i)//执行了 n次 循环
        {
            sum += 1;//执行力 n 次
        }
        System.out.println(sum);
    }
}

由于 循环真正有意义的 执行语句在循环内部,所以 我们应该忽略 循环的 次数。
执行总次数:n + 1 + 1 = n + 2 (次)

  • 第二种解法:
//如果输入量 n 为 1,则需要计算 1 次;
//如果输入量 n 为1亿,则需要计算1一次;
//当你只考虑 输入规模和策略方案的时候,你就会发现我们所谓的效率,就可以用执行 多少次代码 来衡量!!
public class 执行代码次数 {
    public static void main(String[] args) {
        /*int sum = 0;//执行1次
        int n = 100;//执行1次
        for(int i = 1;i<=n;++i)//执行了 n次 循环
        {
            sum += 1;//执行力 n 次
        }
        System.out.println(sum);*/
        
        //执行 1次
        int sum = 0;
        //执行 1次
        int n = 100;
        //执行 1次
        sum = (n+1)*n/2;
        System.out.println(sum);
    }
}

**执行总次数:1 + 1 + 1 = 3 (次) **

因此,当输入规模 为 n时,我们只考虑 算法策略和输入规模的时候!就可以用 代码的执行总次数来衡量代码的效率。第一种算法是 n + 2 次,第二种算法 仅仅只有 3 次,我们忽略 小数量级,会发现 这相当于 n 与 1 的差距!

所以我们说 第二种方法 是 比较快的!

原理:如果我们设 计算机 1 秒 执行代码的次数 为 108,那么 我们只需要 计算出 算法的 执行代码次数,就可以 根据公式 计算出 需求的时间(时间 = 执行代码的次数/108


疑问①:为什么循环和判断 在算法中,执行的次数 要被疏略掉呢??

答:我们来看一个例子!

需求:100个1 + 100个2 + 100个3 + … + 100个n

int sum = 0;
        int n = 100;
        for(int i = 1;i<=n;++i)
        {
            for(int j = 1;j<=n;++j)
            {
                sum+=i;
            }
        }
        System.out.println(sum);

上面这个例子中,如果 我们要精确的研究循环的条件执行了多少次,是一件很麻烦的事情,并且,由于真正与计算相关的代码是在循环内部的,所以,在研究算法的效率时,我们仅仅 只需要考虑核心代码的执行次数,就可以 进行一个大概的比较。


那么有的人肯定会问,这样的话,是不是草率了?
答:并不草率,如果两个算法核心代码的执行次数,差不太多,那我们就可以认为这两个算法差不太多!!!因为随着科技的发展,计算机硬件越来越强大,运算的速度越来越快,即使 我们数据量到达 了 上亿,其实 最后的 丝毫误差,也不会差距太大。(这还 得说是 在 企业大型的项目中,要不然哪来那么庞大的数据??

后来随着人们意识到,只要计算核心代码执行次数就可以衡量算法的效率。那么我们是否可以研究一个 比较 “成熟的方法”,来进行这种 计算核心代码执行次数呢?

答:是可以的,这个比较 成熟的方法,被我们称为 “时间复杂度”。(而进一步优化式子的 方法 叫做 “大O表示法”

时间复杂度:侧重于核心代码的执行次数!


大O表示法:优化时间复杂度的 式子,使其 小数量级的参数自动忽略掉,只保留大数量及的参数!

我们研究算法复杂度,侧重的是当输入规模不断增大时(n),算法的增长量的一个抽象(规律),而不是精确地定位需要执行多少次,因为如果这样的话,我们又得考虑回 编译期优化等问题,容易主观和客观上颠倒!

我们不关心编写程序所用的语言是什么,也不关心这些程序将跑在什么样的计算机上,我们只关心它所实现的算法。这样,不计那些循环索引的递增和循环终止的条件、 变量声明、打印结果等操作,最终在分析程序的运行时间时,最重要的是把程序看做是独立于程序设计语言的算法或一系列步骤。我们分析一个算法的运行时间,最重要的就是把黑心操作的次数和输入规模关联在一起就可以了 ~~~
在这里插入图片描述

n2 、 n 、 1 这样的时间复杂度 是怎么计算出来的?怎么会这么正好??


答:大O 表示法 对时间复杂度 式子的优化!
比如说: O(n) = n2 + n + n/2 +9956 = n2

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值