目录
算法求解的时间效率
在设计算法时,我们通常关注算法的时间效率。然而,由于不同计算机的软件和硬件差异,直接通过程序的执行时间来评估算法效率并不可靠。因此,我们通常通过统计算法在求解过程中计算机执行的语句总次数来估算算法的运行时间。对于同一个问题,当采用不同算法时,求解过程中语句的执行次数越少,意味着该算法的效率越高。
时间复杂度
一个语句的频度是指该语句在算法中被重复执行的次数。事实上,算法中所有语句的频度之和与算法中处于最里层的语句的频度数量级相当。对于下面的代码:
int arr[n];
for(int i=0;i<n;i++)
arr[i]=i;
该代码的频度和(即所有语句的总执行次数)为n,数量级也为n。
对于下面的代码:
int arr[n][n];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
arr[i][j]=i+j;
该代码的频度和为(n个n的和),数量级也为
。
是如果某个算法的频度和为2+3n+4,该代码的数量级也为
。这里可以理解为假设n在无穷的广度下,
的常数系数、3n和4对于总算法的时间效率影响很小,可以忽略。
这里给出时间复杂度的定义:时间复杂度是算法中基本运算的执行次数的数量级,主要关注的是算法在不同输入规模下的运行时间。对于一个输入规模为 n 的问题,时间复杂度表示的是该问题的规模 n增大时,算法执行所需的基本操作次数的增长情况。
时间复杂度记为O(频度),表示总频度的数量级。
事实上时间复杂度不但与n有关,也与数据的性质有关。
对于数组按值查找代码:
int e=1;
for(int i=0;i <n;i++)
if(arr[i]==e)
return i;
如果数组的第一个元素为1,则代码的总频度为1;如果数组的最后一个元素为1,则代码的总频度为n。在这两种不同的情况下,算法的时间复杂度也有所不同。
这里作出以下规定:
- 最坏时间复杂度:最坏情况下,算法的时间复杂度。
- 平均时间复杂度:所有可能输入实例在等概率出现的情况下,算法的期望运行时间。
- 最好时间复杂度:最好情况下,算法的时间复杂度。
一般而言,算法的时间复杂度指的是最坏时间复杂度。
时间复杂度的求解
一般算法时间复杂度的求解
从最本质上来说,算法的时间复杂度的计算等同于基本语句执行次数的计算。基于这个原则与循环运行的特性可以给出下面两个时间复杂度的分析原则:
1加法规则
如果一个算法可以分解为两个或多个子部分,且这些部分是依次执行的(即没有嵌套关系),那么算法的总时间复杂度是各部分时间复杂度的最大值。
E:
int algorithm(arr):
# 部分 1:遍历数组,计算总和
total = 0
for x in arr: # O(n)
total += x;
# 部分 2:找到数组中的最大值
max_val = arr[0]
for x in arr: # O(n)
if x > max_val:
max_val = x;
部分 1 的时间复杂度为 O(n)。
部分 2 的时间复杂度也为 O(n)。
总时间复杂度为 O(n)+O(n)=O(n)。
2乘法规则
如果一个算法的某些部分是嵌套执行的(即一个部分在另一个部分的每次执行中都要完全执行一次),那么算法的总时间复杂度是各部分时间复杂度的乘积。
E:
Void nested_loops(arr):
for i in arr: # O(n)
for j in arr: # O(n)
print(i, j)
外层循环的时间复杂度为 O(n)。
内层循环在外层每次迭代中都执行 O(n)次。
总时间复杂度为 O(n)×O(n)=O(
)。
根据上面的两个规则,可以解决大多数时间复杂度的求解问题,下面是几个算例:
算例
E1:
void fun(int n){
int i=l;
while(i<=n)
i=i*2;
}
计算过程:
假设执行了m次后程序终止,则有
,解得m=log2n,故算法的时间复杂度为O(log2n)。
E2:
int m=0,i,j;
for(i=l;i<=n;i++)
for(j=1;j<=2*i;j++)
m++;
计算过程:
当i=1,则内层循环终止条件为j<=2,基本语句执行次数为2;
当i=2,则内层循环终止条件为j<=4,基本语句执行次数为4;
当i=3,则内层循环终止条件为j<=6,基本语句执行次数为6;
...
当i=n,则内层循环终止条件为j<=2n,基本语句执行次数为2n,此时算法结束;
故算法执行的总次数m=2+4+6+8+...+2n。根据等差数列求和公式,可以得到基本语句的执行次数为
,算法的时间复杂度为O(
)
E3:
int sum=0;
for(int i=l;i<n;i*=2)
for(int j=0;j<i;j++)
sum++;
计算过程:
这里先计算外层循环的执行次数。令t为外层循环的执行次数,则有
,得到
(
默认视为log2n)。
再判断内层循环的执行次数:
当i=1,则内层循环终止条件为j<=1,基本语句执行次数为1;
当i=2,则内层循环终止条件为j<=2,基本语句执行次数为2;
当i=4,则内层循环终止条件为j<=4,基本语句执行次数为4;
当i=8,则内层循环终止条件为j<=8,基本语句执行次数为8;
...
当i=n,则内层循环终止条件为j<=n,基本语句执行次数为n,此时算法结束;
故算法执行的总次数为
,这里是一个等比数列,其中首项为1,项数为logn,应用求和公式
得到算法时间复杂度为O(n)。