数据结构——时间复杂度
一、算法复杂度:
1.⼀个算法的好坏,⼀般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。时间复杂度主要衡量⼀个算法的运⾏快慢,⽽空间复杂度主要衡量⼀个算法运⾏所需要的额外空间。我们当今主要关注时间复杂度。
2.评估算法的好坏:复杂度。
二、时间复杂度:
1.复杂度是一个粗估的概念,并不是一个精确的数字。
2.程序运行的效率:
每条语句运行的时间(编译环境,运行环境(不确定的))*运行次数(确定的),所以算法的时间复杂度是根据运行次数决定的。执⾏次数就可以代表程序时间效率的优劣。
3.例如以下这个函数的时间复杂度函数式T(N)如下:
void Func(int n)
{
int count=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
++count;
}
}
for(int k=0;k<2*n;k++)
{
++count;
}
int m=10;
while(m--)
{
++count;
}
}
T(N)=NN+2N+10; 其中NN即N2占T(N)主导,所以T(N)=N2;
4.我们知道当N不断变⼤时常数和低阶项对结果的影响很⼩,所以我们只需要计算程序能代表增⻓量级的⼤概执行次数,复杂度的表⽰通常使⽤⼤O的渐进表⽰法。
通过以上方法,可得到Func的时间复杂度为:O(N^2)。
5.⼤O的渐进表⽰法
⼤O符号(Big O notation):是⽤于描述函数渐进⾏为的数学符号
推导⼤O阶规则
1. 时间复杂度函数式T(N)中,只保留最⾼阶项,去掉那些低阶项,因为当N不断变⼤时, 低阶项对结果影响越来越⼩,当N⽆穷⼤时,就可以忽略不计了。(保留高阶项)
2. 如果最⾼阶项存在且不是1,则去除这个项⽬的常数系数,因为当N不断变⼤,这个系数 对结果影响越来越⼩,当N⽆穷⼤时,就可以忽略不计了。(项数中存在常数系数,可以去掉系数)
3. T(N)中如果没有N相关的项⽬,只有常数项,⽤常数1取代所有加法常数。(用O(1)来表示常数复杂度)
6.时间复杂度计算实例:
(1).T(N)= 2N +10——>O(N);(如果最⾼阶项存在且不是1,则去除这个项⽬的常数系数。)
(2).T(N)=M+N——>O(M+N); (M,N均为变量)
(3).T(N)=100——>O(1);
(4).
void func(int n)
{
int cnt=1;
while( cnt < n )
{
cnt*=2;
}
}
当n=2时,执行次数为1
当n=4时,执行次数为2
当n=16时,执行次数为4
假设执行次数为x,则2^x=n
所以执行次数x=logn
x=log2 n ;所以是O(logn);不写底数的原因是2x,3x,4^x这些数对于计算机来说,底数的大小可以忽略不计
⼤O的渐进表⽰法在实际中⼀般情况关注的是算法的上界,也就是最坏运⾏情况。
(5).递归的时间复杂度:
假设调用了N次,调用一次函数的时间复杂度为O(1),那递归的时间复杂度就是O(N);即单次递归的时间复杂度*递归的数。
三、空间复杂度
1.空间复杂度计算规则基本跟时间复杂度类似,也使⽤⼤O渐进表⽰法。
注意:函数运⾏时所需要的栈空间(存储参数、局部变量、⼀些寄存器信息等)在编译期间已经确定好 了,因此空间复杂度主要通过函数在运⾏时候显示申请的额外空间来确定。
2.看定义了几个空间,常数个的话,空间复杂度均为O(1).
递归的话,如果函数递归调⽤了N次,额外开辟了N个函数栈帧,每个栈帧使⽤了常数个空间那么空间复杂度为:O(N)。
3.动态申请内容也会涉及空间复杂度的计算
例如:
int arr[n]=malloc(sizeof(int)*n) ——-> O(N);
最后,希望对你有帮助!有任何问题或者是需要进一步的解释,欢迎在评论区留言哦~