数据结构与算法-04-复杂度分析(下)

一、复杂度分析的4个概念

1

2

3

4

5

6

7

8

9

10

11

12

// n 表示数组 array 的长度

int find(int[] array, int n, int x) {

  int i = 0;

  int pos = -1;

  for (; i < n; ++i) {

    if (array[i] == x) {

       pos = i;

       break;

    }

  }

  return pos;

}

1.最坏情况时间复杂度:代码在最理想情况下执行的时间复杂度。

  要查找的变量 x 正好是数组的第一个元素

2.最好情况时间复杂度:代码在最坏情况下执行的时间复杂度。

  如果数组中没有要查找的变量 x,我们需要把整个数组都遍历一遍

3.平均时间复杂度:用代码在所有情况下执行的次数的加权平均值表示。

  我们把每种情况下,查找需要遍历的元素个数累加起来,然后再除以n+1,就可以得到需要遍历的元素个数的平均值,即:

我们知道,要查找的变量 x,要么在数组里,要么就不在数组里。这两种情况对应的概率统计起来很麻烦,为了方便你理解
我们假设在数组中与不在数组中的概率都为1/2。另外,要查找的数据出现在 0~n-1 这n个位置的概率与时一样的,为1/n。所以,根据概率乘法法则,要查找的数据出现在 0~n0~n-1 中任意位置的概率就是 1/(2n)。

因此,前面的推导过程中存在的最大问题就是,没有将各种情况发生的概率考虑进去,如果我们把每种情况发生的概率也考虑进来
那么平均时间复杂度的计算过程变成了这样:

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

二、均摊时间复杂度:

 平均复杂度只在某些特殊情况下才会用到,而均摊时间复杂度应用场景它比较特殊、更加有限有限

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

// array 表示一个长度为 n 的数组

// 代码中的 array.length 就等于 n

int[] array = new int[n];

int count = 0;

void insert(int val) {

   if (count == array.length) {

      int sum = 0;

      for (int i = 0; i < array.length; ++i) {

         sum = sum + array[i];

      }

      array[0] = sum;

      count = 1;

   }

   array[count] = val;

   ++count;

}

我先来解释一下这段代码

1、这段代码实现了一个往数组中插入数据的功能。
2、当数组满了之后也就是代码中的 count == array.length时,我们用for循环遍历数组求和,并清空数组,将求和之后的sum值放到数组的第一个位置
3、然后再将新的数据插入。但如果数组一开始就有空闲空间,则直接将数据插入数组

最理想的情况下,数组中有空闲的空间,我们只需要将数据插入到数组小表为count的位置就可以了 复杂度为O(1)
最坏的情况下:数组中没有空闲空间;额,我们需要先做一次数组的遍历求和,然后再将数据插入,所以最坏情况时间复杂度为 O(1)

平均时间复杂度是:O(1)

假设数组的长度是 n,根据数据插入的位置的不同,我们可以分为n种情况
每种情况的时间复杂度是 O(1)。除此之外,还有一种“额外”的情况,就是在数组没有空闲空间时插入一个数据,这个时候的时间复杂
度是 O(n)。而且,这 n+1 种情况发生的概率一样都是 1/(n+1)。所以,根据加权平均的计算方法,我们求得得的平均时间复杂度就是:

在代码执行的所有复杂度情况中绝大部分是低级别的复杂度,个别情况是高级别复杂度且发生具有时序关系时,可以将个别高级别复杂度均摊到低级别复杂度上。基本上均摊结果就等于低级别复杂度。

均摊时间复杂度就是一种特殊的平均时间复杂度

三、几个为什么?

1、为什么要引入这4个概念?

1.同一段代码在不同情况下时间复杂度会出现量级差异,为了更全面,更准确的描述代码的时间复杂度,所以引入这4个概念。

2.代码复杂度在不同情况下出现量级差别时才需要区别这四种复杂度。大多数情况下,是不需要区别分析它们的。

2、用生活中的例子解释这四个概念

今天你准备去老王家拜访下,可惜老王的爱人叫他去打个酱油,她告诉你说她限时n分钟🕒给他去买。那么你想着以他家到楼下小卖部来回最多一分钟,

最好的情况

那么 “最好的情况”就是你只用等他一分钟。

最坏的情况:

那么也有可能遇到突发情况,比如说电梯人多吖,路上摔了一胶,天知道他去干了什么,用了n分钟,没办法👐,主上有令,n分钟限时,那这就是“最坏的情况”。

平均时间复杂度:

难点,平均时间复杂度 就是他有可能是第1.2.3...n,中的某个分钟回来,那平均就是1+2+3+...n/n,把所有可能出现的情况的时间复杂度相加除以情况数 。

均摊时间复杂度:

均摊的话就是把花时间多的分给花时间少的,得到一个中间值,所以说这就会和平均混淆,个人觉得主要还是概念不同。假如n是10分钟,那么9分钟分4分钟到1分钟那,8分3给2...,那均摊下来就是5分钟.

3、如何分析平均、均摊时间复杂度?

1.平均时间复杂度

代码在不同情况下复杂度出现量级差别,则用代码所有可能情况下执行次数的加权平均值表示。

2.均摊时间复杂度

两个条件满足时使用:

1)代码在绝大多数情况下是低级别复杂度,只有极少数情况是高级别复杂度;

2)低级别和高级别复杂度出现具有时序规律。均摊结果一般都等于低级别复杂度。

四、课后思考题

1、题目

我们今天学的几个复杂度分析方法,你都掌握了吗?你可以用今天学习的知识,来分析一下下面这个 add() 函数的时间复杂度。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

// 全局变量,大小为 10 的数组 array,长度 len,下标 i。

int array[] = new int[10];

int len = 10;

int i = 0;

// 往数组中添加一个元素

void add(int element) {

   if (i >= len) { // 数组空间不够了

     // 重新申请一个 2 倍大小的数组空间

     int new_array[] = new int[len*2];

     // 把原来 array 数组中的数据依次 copy 到 new_array

     for (int j = 0; j < len; ++j) {

       new_array[j] = array[j];

     }

     // new_array 复制给 array,array 现在大小就是 2 倍 len 了

     array = new_array;

     len = 2 * len;

   }

   // 将 element 放到下标为 i 的位置,下标 i 加一

   array[i] = element;

   ++i;

}

参考:

http://www.cnblogs.com/luoahong/ 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值