时间复杂度和空间复杂度(一)

时间:2022-06-19 17:08:36

算法效率的度量方法

比较容易想到的就是我们把算法跑若干次,然后拿计时器在旁边计时,这种方法貌似不错,但是不需真正的计时器来计时,可以利用计算机计时

事后统计法:这种方法主要是通过设计好的测试程序和数据,利用计算机计时器对不同算法编制的程序的运行时间进行比较,从而确定算法效率的高低。

 

但是,这种算法有很大的缺陷:

一、必须依据算法事先编制好的测试程序,通常需要花费大量时间和精力,完了发觉测试的是糟糕的算法,那不是功亏一篑?

二、不同的测试环境差别不是一般的大!

 

因此这个方法不推荐

为了对算法的评判更为科学和便捷,研究出了事前分析估算的方法

事前估算方法:在计算机编写程序之前,依据统计方法对算法进行估算。

 

影响算法效率的因素:

1)算法采用的策略,方案

2)编译产生大代码质量

3)问题的输入规模

4)机器执行指令的速度

 

因此抛开与计算机硬件、软件有关的因素,一个程序的运行时间依赖于算法的好坏和问题的输入规模。

 

第一种算法例子:

时间复杂度和空间复杂度(一)

一共执行了1+1+1+n+1+n = 2n+4

第二种算法:

时间复杂度和空间复杂度(一)

一共执行了3

 

如果我们把循环看成一个整体,忽略头尾判断的开销,那么这两次算法其实就是n1的差距。

那循环判断在算法1里边执行了n+1次,看起来是不少的数据量,怎么能说忽略就忽略呢?

请看如下例子:

时间复杂度和空间复杂度(一)

以上的例子需要执行100^2次。

 

这嵌套循环,循环条件i1100,每次都要让j1循环到100次,如果非常较真的研究总共精确执行次数,如果数字不凑巧,那是非常累的。

另外,我们研究算法的复杂度,侧重的是研究算法随着输入规模扩大增长量的一个抽象,而不是精确地定位需要执行多少次,因为如果这样的话,我们就又得考虑回编译器的优化问题,然后一直这样没完没了。

我们不关心编写程序所用的语言是什么,也不关心这些程序将跑在什么样的计算机上,我们只关心它所实现的算法。

这样,不计较那些恶循环索引的递增和循环终止条件、变量声明、打印结果等操作。最终,在分析程序的运行时间时,最重要的是把程序看成是独立于程序设计语言的算法或一系列步骤。

我们在分析一个算法的运行时间时,重要的是把基本操作的数量和输入模式关联起来。

 

函数渐进增长

导入:判断以下两个算法AB哪个更好?

1、假设两个算法的输入规模都是n,算法A要做2n+3次操作,算法B要做3n+1次操作,你觉得哪个更快一点?

规模

算法A2n+3

算法A12n

算法B3n+1

算法B1(3n)

n = 1

5

2

4

3

N = 2

7

4

7

6

N = 3

9

6

10

9

N = 10

23

20

31

30

N = 100

203

200

301

300

 

解析:当n= 1时,算法A效率不如算法B;当n=2时,两者效率相同;当n>2时,算法A就开始优先于算法B,随着n的增加,算法A比算法B逐步拉大差距。所以总体上算法A比算法B优秀。

 

函数的渐进增长:给定的两个函数f(n)g(n),如果存在一个整数N,对于所有的n>Nf(n)总是比g(n)大,那么我们说f(n)的增长渐进快于g(n)

 

从刚才的对比可以发现:随着n的增长,后面+1+3并不影响最终算法的变化曲线的。

例如以上例题中的算法A和算法B,所以我们可以忽略这些加法常数。

 

2、算法C4n+8,算法D2n^2+1

规模

算法C(4n+8)

算法C1(n)

算法D(2n^2+1)

算法D1n^2

N = 1

12

1

3

1

N = 2

16

2

9

4

N = 3

20

3

19

9

N = 10

48

10

201

100

N = 100

408

100

20001

10000

N = 1000

4008

1000

2000001

1000000

通过上图可观察发现,当n的值无穷时,哪怕是去掉与n相乘的常数,两者的结果还是没有改变,算法C1随着时间的增长远远小于D1。也就是说,与最高次项相乘的常数并不重要,也可以忽略。

 

3、算法E2n^2+3n+1,算法F2n^3+3n+1

规模

算法E2n^2+3n+1)

算法E1n^2

算法F2n^3+3n+1

算法F1(n^3)

N = 1

6

1

6

1

N = 2

15

4

23

8

N = 3

28

9

64

27

N = 10

231

100

2031

1000

N = 100

20301

10000

2000301

1000000

这次,我们通过上图发现,最高项的指数大的,函数随着n的增长,结果也会变得增长的特别就快。

 

4、算法G2n^2,算法H3n+1,算法I2n^2+3n+1

规模

算法G2n^2

算法H(3n+1)

算法I2n^2+3n+1

N = 1

2

4

6

N = 2

8

7

15

N = 5

50

16

66

N = 10

200

31

231

N = 100

2000

301

20301

N = 1000

2000000

3001

200301

N = 10000

200000000

30001

200030001

N = 100000

20000000000

300001

20000300001

N = 1000000

2000000000000

3000001

2000003000001

这组数据很清楚的显示出,当n的值变得非常大的时候,3n+1已经没法和2n^2的结果相比较,最终几乎可以忽略不计,而算法G跟算法I基本已经重合了

于是,我们得到一个结论,判断一个算法的效率时,函数中的常数和其他次要项常常可以忽略,而更应该关注最高项的阶数