数据结构——复杂度

一、复杂度理解

  • 复杂度是数量级 (方便记忆、推广),不是具体的数字

  • 程序执行时需要的计算量和内存空间(和代码是否简洁无关)

  • 一般针对一个具体的算法,而非一个完整的系统

一般分为空间复杂度和时间复杂度。

二、空间复杂度

一个程序的空间复杂度是指该程序的运行所需内存的大小。

空间复杂度也是一个数学表达式,是对一个算法在运行过程种

1.为什么对空间复杂度感兴趣?

  • 如果一个程序要运行在一个多用户计算机系统中,那我们需要指明该程序所需内存的大小。
  • 在任何一个计算机系统上运行程序,都需要知道是否有足够的内存可以来运行该程序。
  • 一个问题可能有若干个解决方案,它们对内存的需求各个不同。比如,对于某些计算机来说,一个C++编译器仅需要1MB的空间,而另一个C++编译器则需要4MB的空间。如果某些计算机的内存少于4MB,则只能选择1MB的C++编译器。如果较小的编译器和较大的编译器有着同样的作用,那么即使用户的计算机有更多内存,也会选择较小的编译器,以便把更多的内存留作他用。
  • 利用空间复杂度,我们可以估算一个程序所能解决的问题最大可以是什么规模。比如,一个电路模拟程序要模拟一个具有x个元件和y个连线的电路,需要10^6+100(c+w)个字节的内存。如果可用内存的总量是5.01×10^8字节,那么最大可以模拟c+w≤5 000 000的电路。

2.空间复杂度的组成

指令空间(instruction space)

指令空间是指编译之后的程序指令所需要的存储空间。

指令空间的数量取决于如下因素:

  • 把程序转换成机器代码的编译器。
  • 在编译时的编译器选择。
  • 目标机器。

   在决定最终代码需要多少空间的时候,编译器是一个最重要的因素。图1-1是计算表达式a + b +b*c+(a +b -c)/(a +b) + 4的三段可以的代码,他们所需要的空间不一样。每一个代码都能由相应的编译器产生。

图1-1

LOADaLOADaLOADa
ADDbADDbADDb
STOREt1STOREt1STOREt1
LOADbSUBcSUBc
MULTcDIVt1DIVt1
STOREt2STOREt2STOREt2
LOADt1LOADbLOADb
ADDt2MULcMULc
STOREt3STOREt3ADDt2
LOADaLOADt1ADDt1
ADDbADDt3ADD4
SUBcADDt2
STOREt4ADD4
LOADa
ADDb
STOREt5
LOADt4
DIVt5
STOREt6
LOADt3
ADDt6
ADD4
 A)B)C)

    即使采用相同的编译器,编译后的程序代码也可能不同。例如,一个编译器可能具备优化选项,如代码大小的优化和执行时间的优化等。在非优化模式下,编译器产生的是图1-1B)的代码。在优化模式下,编译器可能利用知识a+b +b*c=(a+b)+b*c而产生了图1-1C)所示更快、更高效的代码。使用优化模式会增加程序编译的时间。

一个程序还可能需要其他的额外的空间,如t1、t2...临时变量所占用的空间。

数据空间(date space) 

    对于各种数据类型,C/C++语言并没有指定他们的空间大小,只是大多数C/C++编译器有相应的空间分配,例如int,char...数据类型所占空间大小不同,范围也不同。

  一个结构变量的空间大小是每个结构成员所需的空间大小之和。类似的,一个数组的空间大小是数组的长度乘以一个数组元素的空间大小。

类型空间大小(字节数)范围
bool1{true,false}
char1[-128,127]
unsigned char1[0,255]
short2[-32768,32767]
unsigned short2[0,65535]
int4[-2^31,2^21-1]
float4±3.4E±38(7位)
double8±1.7E±308(15位)

                                                        

  考虑如下数组声明:

double a[100];

int b[rows][cols];

  当计算分配给一个数组的空间时,我们只关心分配给数组元素的空间。数组a的空间是100个double类型元素所占用的空间。若每个元素空间是8个字节,则数组a的空间是800个字节。

三、时间复杂度

一、时间复杂度的组成

   时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个算法执行所耗费的时间,从理论上说,是不能算出来的,只有我们把程序放在机器上跑起来,才能知道。

   但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个分析方式。一个算法所花费的时间与其中语句的执行次数成正比例。算法中的基本操作的执行次数,为算法的时间复杂度。

    即:找到某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度。 

二、操作计数

  估算一个程序或者函数的时间复杂度,一种方法是选择一种或多种关键操作 ,例如加、减...然后确定每一种操作的执行次数。

例一

  此函数的表达式可以表示为:F(N1)=N^2 +2*N +10

   实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里我们使用大O的渐进表示法

渐近表达式即为取表达式决定的因素(或取最高阶的项)

F(N1)取决定的因素为N^2,因此Func1的时间复杂度为O(N^2)

例二

此函数的表达式可以表示为:F(N2)=2*N +10

但是Func2的时间复杂度为O(N),这是因为当N取无穷时2N和N并无区别。

常见的时间复杂度量级

常数阶O(1)
对数阶O(logN)
线性阶O(n)
线性对数阶O(nlogN)
平方阶O(n2)
立方阶O(n3)
K次方阶O(nk)
指数阶(2n)

上面从上至下依次的时间复杂度越来越大,执行的效率越来越低。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值