a*算法的时间复杂度_数据结构与算法(一)时间、空间复杂度

9ae7186a17eb1be2ac0027a1e72ca7d5.png

前言

古往今来,任何牛掰的武林绝学例如:九阳神功、葵花宝典、降龙十八掌等武林秘籍无不令武林中人心驰神往,每一个武功背后都是一个个屌丝逆袭高富帅赢取白富美的故事,但是这些故事的主人公无不是机缘巧合下先获得几十年的强大内功,才可以轻松习得这些功法,所以作为路人甲想成为故事的主角,必然要先从拥有扎实的内功基础,再配合各种武林绝学,才可以称霸武林,号令群雄!所谓为了各位武林中人的英雄梦,在此分享本萌主的内功心法修炼之路,嘿嘿e54b0c64900f8ac8d36e69ec33e52ce4.pnge54b0c64900f8ac8d36e69ec33e52ce4.png

正文

开场白有点多,来人拦住那个拔刀的兄弟。。。

为了让广大读者轻松学习,完全理解内容表达含义。我会用最通俗易通的方式结合图文表达,让每位读者完全熟记每种数据结构和算法的优缺点!今天我们分享的是时间复杂度和空间复杂度,因为只要讲到数据结构与算法,就一定离不开时间、空间复杂度分析。

时间复杂度

首先,什么是时间复杂度?简单的讲就是指执行这个算法所需要的执行时间,分为事先统计法和事后统计法,事后统计法就是通过一些监控,指标,来评估算法的时间复杂度,但是这样算法的执行时间,会受到很多因素的影响,例如硬件、运行时环境、数据规模等。所以我们采用事前统计法来评估一个算法不依赖于其他环境因素的影响下的效率。

大 O 复杂度表示法

大O复杂度表示法是指所有代码的执行时间 T(n) 与每行代码的执行次数 n 成某种有规律的函数。例如以下例子一:

 int count(int n) {   int sum = 0;   for (int j = 0; j <= n; ++j) {     sum = sum + j;   } }

上图代码中,假如每行代码的执行一次的时间为一个单位的time,那么第三行1个time,第4,5行都运行了n次,那么总执行时间就是T(n)=(2n+1)time,通过公式我么你可以看出,所有代码的执行时间 T(n) 与每行代码的执行次数 n 成正比,即T(n) = O(f(n)),T(n) 表示代码执行的时间;n 表示数据规模的大小;f(n) 表示每行代码执行的次数总和,因为代码执行次数总和是一个公式,所以用 f(n) 来表示。公式中的 O,表示代码的执行时间 T(n) 与 f(n) 表达式成正比,在例如下面这个例子二:

 int count(int n) {   int sum = 0;   for (int j = 0; j <= n; ++j) {     for (int i = 0; i<=n; ++i){         sum = sum + j + i;     }   } }

以上代码中,代码执行总次数是第二行1个time,第三行执行了n次,所以是n个time第4,5行执行了n^2次,所以总执行时间是(1+n+n^2)time,所以用大O表示就是时间复杂度是T(n)=O(f(n))=O(1+n+n^2)。这就是大 O 时间复杂度表示法,大 O 时间复杂度实际上并不具体表示代码真正的执行时间,而是表示代码执行时间随数据规模增长的变化趋势,所以,也叫作渐进时间复杂度,简称时间复杂度。

时间复杂度分析方法

我们在计算一个算法的时间复杂度的时候通常会忽略掉公式中的常量、低阶、系数,只统计一个最大量级的记录就行了,所以通常统计的方法有以下三种:

  1. 只关注循环执行次数最多的一段代码

    例如在例子一中:第2行只执行了一次,是常量级的执行时间,所以与n无关,但是第3、4行执行了n次,所以我们只关系执行次数最多的第3、4行,所以时间复杂度是O(n)。

    int count(int n) {     int sum = 0;       for (int j = 0; j <= n; ++j) {        sum = sum + j;   } }
  2. 总复杂度等于量级最大的那段代码的复杂度

    如以下例子,在同一个getCount(int n)方法中,第一段for循环的时间复杂度是O(n),第二段for循环的时间复杂度是O(n^2),所以总的复杂度等于量级最大的那段代码的复杂度,所以方法getCount的时间复杂度是O(n^2)。

    public void getCount(int n) {        int sum = 0;        for (int i = 0; i <= n; i++) {            sum = sum + i;        }        int val = 0;        for (int j = 0; j <= n; j++) {            for (int z = 0; z <= n; z++) {                val = val + j + z;            }        }    }
  3. 嵌套代码的复杂度等于嵌套内外代码复杂度的乘积

    同样例如下面的例子,第3行的执行次数是n次,第4、5行的执行次数是n*n=n^2次,所以count方法的时间复杂度是O(n^2)。

    int count(int n) {   int sum = 0;   for (int j = 0; j <= n; ++j) {     for (int i = 0; i <=n; i++){         sum = sum + j + i;     } }

常见时间复杂

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

  空间复杂度

什么是空间复杂度?类比时间复杂度,复杂度是表示算法的存储空间与数据规模之间的增长关系,举个例子:

void setVal(int n) {  int i=0;  int[] a = new int[n];  for(;i         a[i]=i;   }}

如上图,我们声明一个存储变量i,但是由于i是常量阶与n无关,所以我们可以勿略不计,但是第4行我们申请了一个大小是n的int数组,其余没有别的申请空间,所以这个方法的空间复杂度就是O(n),常见的空间复杂度有O(1)、O(n)、O(n^2),至于O(logn)、O(nlogn),几乎很少碰到,所以本文不做讨论,以上就是空间复杂度的分析,更多请类比时间复杂度,因为时间复杂度在一般的面试中被问及的更多,所以讲的比较详细。

最好、最坏、平均、均摊时间复杂度

最后在分享一下时间复杂度中的几个概念,因为这些概念在面试中被问到的频率并不会太多,所以只做一些简单的说明。

  1. 最好情况时间复杂度

    定义:最好情况时间复杂度就是,在最理想的情况下,执行这段代码的时间复杂度

  2. 最坏情况时间复杂度

    定义:最坏情况时间复杂度就是,在最糟糕的情况下,执行这段代码的时间复杂度

    我们还是通过例子来说明:

    int count(int arr[],int x) {     int val = -1;     for (int j = 0; j <= arr.length; j++) {        if(arr[j] == x){             val = arr[j];        }    }    return val;}

    上图例子中,我们从数组arr中查询x的位置,那么最好的情况下就是arr[0]就是x的值,那么只需要查找一次就可以得到x的索引位置并返回,那么我们就说上述代码的最好情况时间复杂度是O(1)。如果在arr中并没有值等于x,那么就需要遍历整个数组,然后返回-1,那么最坏时间复杂度就是O(n)。

  3. 平均情况时间复杂度这个概念有点复杂,需要一点点的数学基础,我们还用上图的例子来说明,我们查找数组中值是变量x的位置,那么一共有n+1种可能:在数组[0~n-1]位置上和 不在数组中,我们把每种情况下,查找x需要遍历的次数累加起来,然后除以n+1,就可以得到需要遍历的元素个数的平均值,就是:bb4a7072245f9c786a39ef4950164b76.png

     然后,我们在计算时间复杂度的大 O 标记法中,可以省略掉系数、低阶、常量,所以,咱们把刚刚这个公式简化之后,得到的平均时间复杂度就是 O(n)。虽然结论是对的,但是计算过程不太准确,因为变量x在不在数组中的概率不一样,我们假在不在数组中的概率都是1/2,那么在数组[0~n-1]每个位置上的概率都是一样的,是1/n,那么根据乘法法则,x在数组中出现的概率就是1/(2n),那么前面推导的公式就变成:

    5b2adcce651fe2b1531ce863a2c94043.png

    这个值就是概率论中的加权平均值,也叫作期望值,所以平均时间复杂度的全称应该叫加权平均时间复杂度或者期望时间复杂度。

  4. 均摊情况时间复杂度均摊情况时间复杂度这里我们不做分析,因为这个复杂度只能说是考试中才有可能考的,面试中基本不会过问,所以我们不做分析,如果又想深入研究的建议google,或者百度大法e90c8ee5edf6952dbfdac27313d99c56.pnge90c8ee5edf6952dbfdac27313d99c56.png

结尾

好了,感谢阅读,d0a2307ad84bd290e4f6fa2dd5e2e73b.pngd0a2307ad84bd290e4f6fa2dd5e2e73b.png本篇文章我们主要讲了时间复杂度和空间复杂度的含义以及分析方法,和一些时间复杂度情况,更多的篇幅还是主要讲解的时间复杂度的分析,这也是因为在面试中,几乎一旦被问到就一定会问时间复杂度的,空间复杂度相对比较容易识别,最后再给大家分享一下常见的数据结构和算法的复杂度总结,那么,我们下期见!

数据结构复杂度对比:

b7a2cffc14b818b9024b0e58ad27be1d.png

常用排序算法复杂度对比:

fd93cf70db90bf81fa203acd8701a01d.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值