1. 如何衡量一个算法的好坏?
衡量一个算法的好坏可以通过算法效率来判断,算法效率又分为空间效率和时间效率,也就是空间复杂度和时间复杂度,时间复杂度主要衡量算法的运行速度,而空间复杂度衡量一个算法所需要的额外空间.
2. 什么是时间复杂度?
什么是时间复杂度,算法中某个函数有n次基本操作重复执行,用T(n)表示,现在有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。简单理解就是用来实现某个功能的一个程序运行的时间
3. 时间复杂度为什么不使用时间来衡量而使用基本语句的运行次数来衡量?
如果用时间来衡量时间复杂度的话,每个程序的时间复杂度需要运行起来才能知道,而且不同的算法有时候差别在0.1毫秒,这就很难判断到底哪个算法比较好,但是用次数来衡量的话,就解决了,而且运行次数和运行时间是成正比的
4. 时间复杂度的O渐进表示法
举一个例子
// 请计算一下Func基本操作执行了多少次?
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;
}
printf("%d\n", count);
}
实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这 里我们使用大O的渐进表示法。
大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。 使用大O的渐进表示法以后,Func的时间复杂度为:
N = 10 F(N) = 100 N = 100 F(N) = 10000 N = 1000 F(N) = 1000000
通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。
另外有些算法的时间复杂度存在最好、平均和最坏情况:
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数 最好情况:任意输入规模的最小运行次数(下界)
在实际中一般情况关注的是算法的最坏运行情况,所以数组中搜索数据时间复杂度为O(N)
5. 时间复杂度的:最优、平均、最差情况,为什么时间复杂度看的是最差情况?
个人看法:工业生产中算效率也是算最低效率,以最低完成量为目标,超额完成或者提前完成不是更好吗
6. 什么是空间复杂度?
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度
7. 如何求空间复杂度? 普通函数&递归函数
主要有三种:
int *a = (int*)malloc(n);//堆上开辟和n相关的空间
int a[n];//栈上开辟空间
//递归函数,调用栈时占用空间和n的关系
注意:空间复杂度中,输入中使用的空间不算在内,比如冒泡排序中传入的数组空间
9. 分析递归斐波那契数列的:时间、空间复杂度,并对其进行优化,伪递归优化—>循环优化
斐波那契数列
long long Fib(int n){
if (n<2){
return n;
}
return Fib(n - 1) + Fib(n - 2);
}
比如n=5;则:
将剩余数字补齐,则时间复杂度近似为O(2^n)
递归过程中,前一次递归占用的内存没有释放,所以空间复杂度为O(n)
循环法相对复杂度小
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int fib(int n)
{
int a = 1;
int b = 1;
int c = 0;
int i = 0;
while (n > 2)
{
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
int main()
{
int n = 0;
printf("求出第n个斐波那契数:n=");
scanf("%d", &n);
printf("%d\n", fib(n));
system("pause");
return 0;
}