美文网首页
数据结构复杂度分析

数据结构复杂度分析

作者: Mind语 | 来源:发表于2020-06-29 09:32 被阅读0次

    我们上一节说道:

    1、数据结构是 数据的存储结构。
    2、算法是对数据的操作。

    数据结构和算法总是在一起的,两者缺一不可。

    那么我们为什么要使用数据结构和算法呢?

    总的来说就是 :更快、更省。

    更快速的处理数据,更省空间的存储数据!

    那么怎么知道数据是否“更快、更省”呢?

    这里就要说到复杂度了。

    可能会有人说,我何必这么麻烦啊呢?
    直接代码跑一跑 ,不就能立马知道代码的耗时了么?

    这个其实也是一种方式,但是 无法准确估量。

    原因有两个:

    1、非常受计算机硬件的性能影响。

    例如i3 和i9处理器,分别跑,时间肯定不一样。

    2、跟数据的量也有很大关系。

    想一想处理10000条数据和处理100万条数据,耗时能一样么?

    所以我们需要一种不受客观条件所影响的方法来粗略的计算效率问题,那就是数据结构的复杂度

    数据结构的复杂度一般分为

    1、时间复杂度
    2、空间复杂度。

    一般我们都使用大O复杂度表示法。

    我们先看一下这端代码的复杂度。

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

    因为我们只能粗略的估计复杂度,那么我们假设 每一段代码的执行时间都是一样的,都是一个uTime时间,那么
    第二行代码执行需要1个uTime,接下来3行4行 是一个for循环,我们可以看出一共会被执行2n个uTime时间,第6行
    会被执行1个uTime时间,那么一共会被执行2(n+1)个uTime时间。

    T(n)=O(2(n+1))

    T(n)代表代码执行时间。

    我们可以看出代码的执行时间跟n的大小成正比。

    接着看下面的代码

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

    依旧假设每一行代码执行时间是uTime,那么第2行 执行时间1个uTime,第3行为n个uTime,第4行 n² 个 uTime,
    第5行 n²个 uTime,那么一共为 (2n²+n+1) 个 uTime。

    T(n)=O(2n²+n+1) ;

    通过这两段代码可以推断出,代码执行时间T(n)跟代码的执行次数n的大小成正比。

    T(n)=O(f(n))
    T(n) 表示代码执行的时间;n 表示数据规模的大小;f(n) 表示每行代码执行的次数总和。

    O表示代码的执行时间 T(n) 与 f(n) 表达式成正比。

    第一个例子: T(n)=O(2(n+1)) ;

    第二个例子:T(n)=O(2n²+n+1) ;

    都是大 O 时间复杂度表示法。

    大 O 时间复杂度实际上并不具体表示代码真正的执行时间,而是表示代码执行时间随数据规模增长的变化趋势,
    所以,也叫作渐进时间复杂度(asymptotic time complexity),简称时间复杂度。

    由于大 O 表示的是一个趋势,所以当n很大的时候,我们可以忽略对增长趋势影响很小的部分,例如第一个例子中的常量1 ,
    使用大O表示法的话就是

    T(n)=O(n)

    第二个例子 去掉 n ,去掉1,去掉常量2 ,因为这些在n足够大的时候,对增长趋势的影响很是微小,学过微积分的童鞋应该很容易理解。

    T(n)=O(n²)

    如何分析大O表示发,阅读王争老师的《数据结构与算法之美》中老师总结了三个方法

    1、只关注执行次数最多的代码。
    例如:第一个例子,只需要关注循环次数n的代码

    2、复杂度等于量级最大的那段代码的复杂度。
    例如 :第二个例子,我们只需要关注 运行次数 n²的代码。

    3、嵌套代码的复杂度等于嵌套代码内外复杂度的乘积。
    看下面的例子:

    int cal(int n) {
       int ret = 0; 
       for (int i = 1; i < n; ++i) {
         ret = ret + sum(i);
       } 
     } 
     int sum(int n) {
       int sum = 0;
       for (int i=0; i <= n; i++) {
         sum = sum + i;
       }
       return sum;
     }
    

    cal中嵌套了sum函数,cal代码的最大执行次数是n,sum同样也是n,会导致sum中第9行的代码,执行n²次。

    常见的时间复杂度实例
    常量阶 O(1)
    对数阶 O(logn)
    线性阶 O(n)
    线性对数阶 O(nlogn)
    平方、次方阶等等 O(n²) 数值可以为2、 3、 k等等。

    指数阶O(2n)
    阶乘O(n!)

    O(1)常量级的比较简单,不再赘述。

    说一下O(logn)的情况

    看一下下面的例子

     i=1;
     while (i <= n)  {
       i = i * 10;
     }
    

    这段代码的复杂度是多少呢?

    假设:n=10时,10×1=10;
    n=100时,10×10×1=100;
    n=1000时,10×10×10×1=1000;

    那么10的x次方等于n,x等于lgn ,如果n足够大,那么不管是以10为底,还是以2、以5为底,却别都不大,所以大O表示为O(logn);

    我们常见的空间复杂度就是 O(1)、O(n)、O(n² ),像 O(logn)、O(nlogn) 这样的对数阶复杂度平时都基本用不到

    同量级复杂度 情况下 O(logn)<O(n)<O(nlogn)<O(n²)

    接下来看一下空间复杂度

    时间复杂度的全称是渐进时间复杂度,表示算法的执行时间与数据规模之间的增长关系。

    与之相似,空间复杂度全称就是渐进空间复杂度(asymptotic space complexity),表示算法的存储空间与数据规模之间的增长关系

    看如下代码

     int[] a = new int[n];
      for (int i=0; i <n; i++) {
        a[i] = i * i;
      }
    

    时间复杂度 O(n),空间复杂度分析一下,我们可以看到代码第一行申请了一个长度为n的数组,其他的行的代码基本都没有占用多少空间,
    所以我们认为这段的空间复杂度也是O(n)

    其他的空间复杂度与时间复杂度分析类似,不再赘述,其实现在我们基本关注的时间复杂度更多一点,由于存储空间目前来说相对很便宜,有时候我们还会
    做出用空间换时间的举措。

    更多内容,欢迎同步关注作者公众号二维码!
    程序员内功修炼手册 主要发布计算机基础、设计模式、计算机网络基础知识,同时重点关注大前端知识
    Android、iOS、web前端、Flutter、React Native等,想学习大前端知识的速度来吧,一起学习、一起成长!


    qrcode_for_gh_f730c342ff6e_344.jpg

    相关文章

      网友评论

          本文标题:数据结构复杂度分析

          本文链接:https://www.haomeiwen.com/subject/gwonfktx.html