计算一些简单的算法时间复杂度。今天算是简单了解了时间复杂度的计算方法。
简单概念
算法的时间复杂度:是指算法的时间度量,
记作 :
T(n) = O(f(n))
其中,
n 为问题的规模。
f(n) 是表示问题规模的某个函数。
T(n) 是算法的时间复杂度。
算法的时间复杂度建立在数据规模与执行次数的函数关系上。所以完整的分析过程是:
1. 分析数据规模与操作次数之间的函数关系
2. 按 大O阶 方法推导算法的时间复杂度
大O阶 方法计算的时间复杂度
推导 大O阶 的方法:
1.用常数 1 取代运行事件中所有加法常数。
2.再修改后的运行次数函数中,只保留最高阶项。
3.如果最高阶项存在,且不是1 , 则去掉最高阶的常数系数。
计算
一层循环
int n = 100;
for(i = 0; i < n; i++){
// C 行代码
}
分析:
第一行代码执行次数 1 次
第二行代码开始为一个 for 循环,循环次数为 100 次。
即,循环体中的 C行代码 执行次数为 Cn 次(一共 C 行,每行执行 n 次)
计算:
f(n) = Cn+1
=>只保留最高阶项
T(n) = O(Cn)
=>去掉最高阶的常数系数
T(n) = O(n)
即,这个 for 循环的时间复杂度为 O(n) , 为 线性阶
二层循环(普通)
int n = 100; // 复杂度计算会忽略
for(int i = 0; i < n; i++){
X 行代码
for(int j = 0; j < n; j++){
Y 行代码
}
} //X 、 Y 为常数
分析:
外层循环次数为 n 次
内层循环次数为 每一次外层循环 执行 n 次
计算:
f(n) = Xn + n * Yn
=>保留最高项
T(n) = O( n * Yn)
=>去掉项数
T(n) = O(n^2)
即,这个 for 循环的时间复杂度为 O(n^2) , 为 平方阶
冒泡排序时间复杂度计算
int[] arrayInt = { 7, 3, 10, 0, 6 };
for (int i = 0; i < arrayInt.length - 1; i++) {
for (int j = 0; j < arrayInt.length - i - 1; j++) {
int temp = 0;
if (arrayInt[j] > arrayInt[j + 1]) {
temp = arrayInt[j];
arrayInt[j] = arrayInt[j + 1];
arrayInt[j + 1] = temp;
}
}
}
分析:
数组长度为 5
外层循环 4 次
内层循环 i = 0 第 1 次 执行 4 次
i = 1 第 2 次 执行 3 次
i = 2 第 3 次 执行 2 次
i = 3 第 4 次 执行 1 次
归纳后:
数组长度 n
外层循环 n-1
内层循环 i = 0 第 1 次 执行 (n-1) 次
i = 1 第 2 次 执行 (n-2) 次
i = 2 第 3 次 执行 (n-3) 次
...
i = (n-3) 第 (n-2) 次 执行 2 次
i = (n-2) 第 (n-1) 次 执行 1 次
计算:
f(n) = (n-1) + (n-2) + (n-3) + ... + 2 + 1
这样理解,外层要执行 n-1 次循环,而每次内层循环的次数都不一样每次要比前一次循环次数少一次,冒泡排序的原理嘛,最后一项不用排序,因为没有下一项。所以第一次排序就是对前 n-1 项进行排序。然后每次排序都会将最大的排到后面(上例)。最后是第一项和第二项比较,结束后的数组就是由小到大排序。说多了。。。
也就是说外层循环控制内层循环总共要执行 n-1 次 ,其中的每一次内层循环的次数都要比前一次内层循环的次数少一次。
即,得到了上面的函数。
继续:
利用等差数列前 n 项和公式
f(n) = [(n-1) + 1] * (n-1) / 2
... 省略计算步骤
T(n) = O(n^2)
总结:
循环结构的时间复杂度是,循环体的时间复杂度 * 该循环运行的次数。
其他复杂的函数(方法嵌套的,递归的)时间复杂度计算方法待研究。