-
如何衡量一个算法的好坏?
算法:用一系列的计算步骤,将输入数据转化为输出结果
算法效率:时间效率(时间复杂度)和空间效率(空间复杂度)
一个算法的好坏取决于这个算法的效率,即时间效率和空间效率,时间和空间效率约高,算法越好。 -
什么是时间复杂度?
算法中的基本操作的执行次数,称为算法的时间复杂度。 -
时间复杂度为什么不使用时间来衡量而使用基本语句的运行次数来衡量?
因为每台计算机的cpu等硬件条件不同,对于同一个算法,计算时间可能会有不同,如果用时间衡量时间复杂度,不具代表性,而每个算法基本语句的运行次数是相同的,所以用基本语句的运行次数来衡量时间复杂度。 -
时间复杂度的O渐进表示法
(1)用常数1取代运行时间中的所有加法常数,例:O(10)=>O(1)
(2)在修改后的运行次数函数中,只保留最高阶项,例:O(N^2+N)=> O(N^2)
(3)如果最高阶项存在且不是1,则去除与这个项相乘的常数,例:O(2N^2)=> O(N^2)
所以,一个算法执行的基本操作次数为N^2+2N+10,时间复杂度为 O(N^2) -
时间复杂度的:最优、平均、最差情况,为什么时间复杂度看的是最差情况?
如果在一个长度为n的数组中查找一个数,最好情况是查找1次,最差情况是查找n次,平均查找n/2次,一个算法应考虑到所有可能出现的情况,而不是只考虑最优情况,所以时间复杂度看的是最差情况。 -
如何求解:二分查找、递归求阶乘、递归斐波那契的时间复杂度?
(1)二分查找
int BinarySearch(int* a,int n,int x)
{
assert(a);
int begin = 0;
int end = n-1;
while(begin<end)
{
int mid = begin+((end-begin)>>1);
if(a[mid]<x)
{
begin=mid+1;
}
else if(a[mid]>x)
{
end=mid;
}
else
{
return mid;
}
}
return -1;
}
二分查找最坏情况为N=2^m,即m=log(2)N,所以时间复杂度为O(log(2)N)
(2)递归求阶乘
long long Factorial(size_t N)
{
return N<2 ? N : Factorial(N-1)*N;
}
递归函数时间复杂度计算方法:单次递归函数中的调用次数*递归函数总的递归次数
对于递归函数求阶乘,单次调用次数为1,总调用次数为N,所以时间复杂度为O(N)
(3)递归斐波那契
long long Fibonacci(size_t N)
{
return N<2 ? N : Fibonacci(N-1) + Fibonacci(N-2);
}
对于递归斐波那契函数,单词调用次数为1,总调用次数为2^N,所以时间复杂度为 O(2^N)
-
什么是空间复杂度?
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的度量。 -
如何求空间复杂度? 普通函数&递归函数
空间复杂度的计算规则与时间复杂度类似,也使用O渐进表示法。
(1)普通函数
void BubbleSort(int* a,int n)
{
assert(a);
for(size_t end=a;end>0;++end)
{
int exchange=0;
for(size_t i=1;i<end;++i)
{
if(a[i-1]>a[i])
{
Swap(&a[i-1],&a[i]);
exchange=1;
}
}
if(exchange==0)
{
break;
}
}
}
对于此冒泡函数,由于没有占用额外的内存空间,所以空间复杂度为O(1)
(2)递归函数
long long Factorial(size_t N)
{
return N<2 ? N : Factorial(N-1)*N
}
对于此递归求阶乘函数,递归调用深度为N,单次递归所需空间为1,所以空间复杂度为O(N)
- 分析递归斐波那契数列的:时间、空间复杂度,并对其进行优化,伪递归优化—>循环优化
(1)递归斐波那契
long long* Fibonacci(size_t n)
{
if(n==0)
{
return NULL;
}
long long* fibArray=new long long[n+1};
fibArray[0]=0;
fibArray[1]=1;
for(int i=2;i<=n;++i)
{
fibArray[i]=fibArray[i-1]+fibArray[i-2];
}
return fibArray;
}
时间复杂度:O(N)
空间复杂度:O(N)
(2)伪递归斐波那契
long Fibonacci(long first,long second,long n)
{
if(n<3)
{
return 1;
}
return Fibonacci(second,first+second,n-1)
}
时间复杂度:O(N)
空间复杂度:O(1)
(3)循环斐波那契
long Fibonacci(long first,long second,long n)
{
int third=0;
if(n<3)
{
return 1;
}
while(n>3)
{
int tmp=second;
second=first+second;
first=tmp;
n--;
}
third=first+second;
return third;
}
时间复杂度:O(1)
空间复杂度:O(1)
- 总结常见时间复杂度
执行10次———————— O(1)
执行2N次———————— O(N)
执行2N^2+N+1次———— O(N^2)
执行log(2)N+1次———— O(log(2)N)
执行2^N+1次—————— O(2^N)