今天来看一下数据结构中的复杂度。
首先说明一下为什么要了解复杂度这个概念呢?复杂度对我们来说有什么用?怎么用?
算法效率:用来衡量算法好坏的一个标准。
long long Fib(int N)
{
if(N < 3)
return 1;
return Fib (N-1)+Fib(N-2);
}
对于斐波那契数列用递归的方式是非常简洁的,但是简洁一定好吗?不一定吧!
算法的复杂度:算法编写成可执行程序的时候,运行肯定要耗费时间和空间(内存)资源的,所以衡量算法的好坏可以从时间和空间来看。即时间复杂度和空间复杂度。
总体来说复杂度分为时间复杂度和空间复杂度。
先来介绍时间复杂度;
1.时间复杂度
顾名思义时间复杂度就是算法中基本操作的执行次数。
递归计算空间复杂度的技巧:
每次递归调用的执行次数累加。
利用大O渐进表示法。
2.空间复杂度
算法复杂度是对一个算法在运行过程中临时占用存储空间的量度。
注意:函数运行时所需要的栈空间(存储参数,局部变量,一些寄存器的信息)即在编译期间确定好了。所以我们在计算空间复杂度的时候主要通过函数在运行时申请的额外空间来确定。
递归计算空间复杂度的技巧:
每次递归调用的变量个数累加。
3.大O的渐进表示法(估算,取最高项)
大O符号:用于描述函数渐进行为的数学符号。
计算大O的方法:
1.用常数1来代替运行中所有加法常数。
2.在修改后的运行次数函数中 ,只保留最高项。
3.如果最高阶项存在且不为1,则去除与这个项目相乘的常数。得到的结果即为大O阶。
举例:
计算下面函数中的count++语句一共执行多少次?
void Fun1(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 <3 * N; k++)
{
count++;
}
int m = 10;
while (m--)
{
count++;
}
pritnf("%d \n", count);
}
F(N) = ( N^2 + 3 * N + 10).
简化后大O--------------> F(N) = O(N^2)。
特殊情况:
有些算法存在最好,平均,最坏的三种情况。
最坏情况:任意输入大小的最大运行次数(上界)。
最好情况:任意输入大小的最小运行次数(下界)。
平均情况:任意输入大小的期望运行次数。
栗子:在一个长度为N数组中寻找数据n。
最好情况:1次找到(寿命献祭(狗头))。
平均情况:N / 2 次找到。
最坏情况:N次找到(献祭失败)。
在实际情况中,我们主要关注的是最坏的运行情况,所以数组中搜素数据的复杂度为O(N).
计算空间复杂度
void Fun1(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 <3 * N; k++)
{
count++;
}
int m = 10;
while (m--)
{
count++;
}
pritnf("%d \n", count);
}
显而易见
F(N) = O(1 + 1);m 和 count
简化后大O--------------> F(N) = O(1)。
栗子:
计算下列递归阶乘的空间复杂度。
long long Fun2(size_t N)
{
if (1 == N)
return 1;
return Fun2(N - 1) * N;
}
F(N) = O(1 + 1);m 和 count
简化后大O--------------> F(N) = O(1)。
这个是递归的空间复杂度计算方法,递归调用的变量个数的累加。
今天的分享就到此结束了,感觉有帮助的小伙伴可以点点关注和赞哦!有不懂也可以私信我!