大O表达式是用来描述算法时间复杂度的重要工具,在Java开发中,我们经常会遇到多段代码先后执行的情况,这时候就需要对多段代码的大O表达式做加法运算,得到整体代码的时间复杂度。

大O表达式加法的核心规则
大O表达式的加法遵循两个核心原则:
- 如果多段代码的复杂度属于不同阶,那么整体复杂度取最高阶的项,低阶项会被忽略。
- 如果多段代码的复杂度属于同阶,那么整体复杂度保留该阶,系数会被忽略。
简单来说,大O加法不是普通数值相加,而是保留对复杂度影响最大的那个项,因为随着输入规模n的增大,高阶项的增长速度会远超低阶项,低阶项的影响可以忽略不计。
Java中不同场景的大O加法示例
场景1:不同阶复杂度相加
下面是一段先后执行不同复杂度代码的Java示例:
public class BigOAddExample1 {
public static void main(String[] args) {
int n = 1000;
// 第一段代码:O(n)复杂度,遍历数组
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = i;
}
// 第二段代码:O(n²)复杂度,双层循环处理数组
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
arr[i] = arr[i] + arr[j];
}
}
// 第三段代码:O(1)复杂度,单次操作
int a = 10;
int b = 20;
int sum = a + b;
}
}这段代码三段的时间复杂度分别是O(n)、O(n²)、O(1),按照加法规则,取最高阶的O(n²),整体代码的时间复杂度就是O(n²)。
场景2:同阶复杂度相加
当多段代码都是同阶复杂度时,系数会被忽略,看下面的示例:
public class BigOAddExample2 {
public static void main(String[] args) {
int n = 1000;
// 第一段:O(n)复杂度,遍历一次数组
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = i;
}
// 第二段:O(n)复杂度,再遍历一次数组
for (int i = 0; i < n; i++) {
arr[i] = arr[i] * 2;
}
}
}两段代码都是O(n)复杂度,相加之后是O(n) + O(n) = O(2n),根据大O表示法的规则,系数2会被忽略,整体复杂度仍然是O(n)。
循环嵌套场景下的加法计算
如果代码中既有顺序执行的代码块,又有嵌套结构,需要先分别计算每个部分的大O,再做加法:
public class BigOAddExample3 {
public static void main(String[] args) {
int n = 1000;
// 部分1:O(n)顺序循环
for (int i = 0; i < n; i++) {
System.out.println(i);
}
// 部分2:嵌套循环,O(n²)
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.println(i + j);
}
}
// 部分3:O(logn)的对数量级循环
int m = n;
while (m > 1) {
m = m / 2;
System.out.println(m);
}
}
}三个部分的大O分别是O(n)、O(n²)、O(logn),取最高阶的O(n²),整体时间复杂度就是O(n²)。
注意事项
在计算大O加法时,需要注意几个常见误区:
- 不要直接把大O的数值相加,比如不要认为O(n)加O(n²)等于O(n + n²),而是直接取O(n²)。
- 只有独立执行的代码块才用加法,嵌套的循环属于乘法规则,不要混淆加法和乘法。
- 当输入规模不大时,大O的近似计算可能和实际运行时间有差异,大O更适合评估输入规模趋近于无穷大时的性能趋势。
掌握大O表达式的加法规则,能帮助我们更快速地评估Java代码的整体时间复杂度,在开发过程中提前发现潜在的性能瓶颈,做出更合理的代码优化决策。