时空复杂度简述
时间复杂度
计算机的运行能力估计:
做一个简单实验,让程序循环1亿次,10亿次看看需要多少时间。
可以看出,一般电脑在1亿次可在1秒内完成,超过10亿次在1秒内难以完成。
时间复杂度估算方法
简单语句
简单的赋值语句,读写语句,可以看作所用时间为常量记为O(1)。
分支语句
在分支语句中,以所耗费时间最多的那个分支来计算时间复杂度。
循环语句
在循环语句中,每循环1次记为O(1),循环n次时间复杂度为O(n)。
嵌套循环
在嵌套循环中,时间复杂度是多个循环的叠加,如下所示:n^2
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
……. O(n*n)=O(n2)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;i++)
……. O(n*n)=O(n3)
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
…..
}
for(int k=1;k<=n;i++){
…….
}
} O(n*n)=O(2*n2)
空间复杂度
我们编写的程序运行时的代码和数据等信息,保存在我们的内存中,我们的内存到底能装多少数据,这个与计算机内存大小,运行其它程序的多少有关。一般来讲全局数据内存大可达到(亿级个整数),局部变量内存较少可达到(千万级个整数)。
数据结构概念
在计算机内存中,不仅存放整数,它可以存放各种不同的数据类型,例如:
struct student{
int num;
char name[10];
int age;
.....
} a,b, c[100];
上面定义的学生结构体中:
student:是一个整体,是计算机的基本存储单元,称为数据元素。
其中num,name,age等 称为一个个数据项
a,b,c[100]等称为具体的数据对象
数据结构中的逻辑结构与物理结构:
在计算机中所有数据在内存都是以0和1的方式保存,本质上没有任何区别,只是为了使程序员设计算法的需要,把这些数据按物理和逻辑上进行分类。
物理结构:是指数据实实在在的存储在内存的方式。一种是按地址连续不断的进行存储,称为顺序存储结构。另一种,数据存储随意,而用其它方式(例如指针)使得这些数据关联起来,称为链式存储结构。无论那种存储结构,数据就是数据,是客观存在的,不带有任何主观意识。
如果把周末在解放碑闲逛的人看作是一个个数据,那么人就是人,不存在任何关系,如果让他们排队去看电影,一个紧靠一个,就构成了顺序存储结构,如果让他们拿号去取钱,人的位置可以随意走动,就构成了链式存储结构。
逻辑结构:就是在开发人员的脑海里,主观地认为这些数据存在某些关联,以实现某种要求,而而认为这些数据存在的结构。如上面的人,无论是排队看电影还是拿号取钱,都依照一定的顺序,存在一对一的关系,这叫线性结构,若是一个家庭在迋解放碑,这样父亲—>儿子—>孙子,存在一对多的关系,这叫树形结构。如果是一个班的同学在迋解放碑,这就构成多对多的关系,这叫图形结构。
所以,物理结构是客观存在的东西,逻辑结构是认为强加的意思,是算法设计与实现不可缺少的部分。
内存管理机制
程序运行将计算机内存分为如下四个区域:
程序代码区:运行程序本身所需要的存储空间,它与程序规模大小有关,一旦程序运行,不能进行动态管理,除非进程杀掉它。
全局数据区:用以存放全局变量、静态变量和常量的地方,生命周期与程序一致,即程序运行它就会占用空间,直到程序结束。
栈区:存放局部变量和形参变量的地方,在函数调用时自动分配,调用完毕后会自动释放,包括主函数。
堆区:动态分配的指针变量,这需要我们手动和手动释放。
函数调用机制
主调函数调用被调函数
主动权给被调函数
为形参和局部变量分配内存
实参与形参匹配传值
被调函数返回主调函数
主动权返回主调函数
计算结果返回
释放形参和局部变量内存空间
循环与递归的时空复杂度
循环1亿次比递归1亿次要快,主要在于函数调用和形参、局部变量分别要花去时间,但都能在1秒内完成。
求1到n的和,循环和递归实现。
int sum(int n){
if(n==1)return 1;
return sum(n-1)+n;
}
当n=100000时,内存溢出。递归调用层次不能过多,它使用的是栈区内存。