一、算法分析
1.1 时间复杂度分析
1.1.1 函数渐近增长
概念:
给定两个函数f(n)和g(n),如果存在一个整数N,使得对于所有的n>N ,f(n)总是比g(n)大,那么我们说f(n)的增长渐近快于g(n)。
算法函数规则的结论:
- 算法函数中的常数可以忽略。
- 算法函数中最高次幂的常数因子可以忽略。
- 算法函数中最高次幂越小,算法效率越高;
最高次幂,就是for循环嵌套的层数;
常数就是非循环的步骤;
最高次幂的常数因子就是for循环的嵌套语句有多少个;
1.1.2.1 大O记法
定义:
在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随着n的变化情况并确实T(n)的量级。记作T(n)=O(f(n))。
规则:
- 用常数1取代运行时间中的所有加法常数。
- 在修改后的运行次数中,只保留高阶项。
- 如果最高阶项存在,且常数因子不为1,则去除与这个项相乘的常数。
1.1.2.2常见的大O阶
- 线性阶
时间复杂度为O(n),就是有单层循环。 - 平方阶
时间复杂度为O(n^2),一般有嵌套循环。 - 立方阶
时间复杂度为O(n^2),一般有三层嵌套循环。 - 常数阶
时间复杂度O(1),只有步骤没有循环。 - 对数阶
//例如
int i=1,n=100;
while(i<n)
{
i=i*2;
}
由于每次i*2之后,就距离n更近一步,假设有x个2相乘后大于n,则会退出循环体。由于2^x=n,得到x=log(2)n。时间复杂度就为O(logn)。因为底数不会影响趋势,所有可以忽略。
时间复杂度低到高
O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)
当复杂度大于或等于O(n^2)时,需要优化。
1.1.2.3 函数调用的时间复杂度分析
//例如
viod main()
{
int i = 0 ,n = 100;
for( i = 0 ; i < n ; i++)
{
show(i)
}
}
void show(int i)
{
for(int j = 0; j < i ; i++)
{
printf("%d",i);
}
}
在show函数里面,有一个for循环,所以show函数的时间复杂度为O(n),在main中有一个for循环,循环体调用了show函数所以main的时间复杂度为O(n^2);
1.1.2.4 最坏情况
//例如
int search (int num)
{
int a[]={11,10,8,6,7,12,23,0}
for(int i =0 ; i <seizof(a) ; i++)
if(num == a[i])
{
return i;
}
return -1;
}
最好情况:查找第一个数字就是期望的数字,那么算法的时间复杂度就是O(1)。
最坏情况:查找最坏一个数字,或者没有找到,那么算法的时间复杂度为O(n)。
平均情况:任何数字查找的平均成本是O(n/2)。