发布于 2026-01-06 14 阅读
0

“大O符号”到底是什么意思?

“大O符号”到底是什么意思?

如果你是一名程序员,你很可能遇到过“大O表示法”这个术语。但它究竟是什么意思呢?

大O表示法用于描述程序或数据结构的计算复杂度。其基本含义是:执行某个操作需要多少步骤。“步骤”在此并非指CPU周期或程序中的代码行数,而是指任意长度固定的步骤,无论其大小如何。

我们先来看一个例子:检查一个元素是否在数组中。在 JavaScript 中,你可以这样实现:

function findInArray(array, element) {
    for(let i = 0; i < array.length; i++) {
        if(array[i] === element) {
            return true;
        }
    }
    return false;
}

你很容易就能看出这一点:循环内的所有操作都耗时恒定:通过索引访问数组元素并进行比较。我们将其定义为 1 个“步骤”。但由于循环的存在for,我们需要执行这些n操作。用大 O 表示法表示为:O(n)

其他用大O符号描述的标准例子包括排序算法。以最简单的排序算法——冒泡排序为例,它的实现可以如下所示:

function bubblesort(array) {
    for(let i = 0; i < array.length; i++) {
        for(let j = 0; j < array.length - 1; j++) {
            if(array[j] > array[j + 1]) {
                let tmp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = tmp;
            }
        }
    }
}

对于数组中的每个元素,循环遍历整个数组,并在需要时交换元素。和之前一样,循环中的所有操作都是常量。然后我们有一个循环执行此n操作 次。但我们还有一个循环,它会执行第一个循环n次。因此,我们总共执行了次n操作n。用大O表示法表示:O(n*n) = O(n²)

但也有其他情况下,答案并非如此简单。例如,请看以下代码片段:

function mapAndFilter(x) {
    return x
        .map(n => n * 2)
        .filter(n => n > 0);
}

这个函数的复杂度是多少?是吗?

  • O(1)
  • O(n)
  • O(n²)
  • 有点不一样?

正确答案是O(n)。为什么?虽然我们的代码本身是恒定的(没有直接循环),但执行其他函数也需要一些时间。在这种map情况下,浏览器会遍历所有元素并对它们调用该函数(因此这将是O(n)),filter这基本上与我们的 相同findInArray,所以也是O(n)。我们的函数加起来将有O(n+n) = O(2n),但大 O 表示法不考虑常数因子,因此2会被省略,最终得到O(n)

我认为这是一个很好的例子,说明你不仅要检查自己的代码,还要检查通过库或浏览器导入的代码。任何操作数据结构的算法都有其计算复杂度。如果你了解这一点,就可以编写复杂度尽可能低的代码。你还可以问自己:“我需要对数据结构执行哪些操作?是否存在复杂度更低的替代数据结构?”

这是关于常见数据结构及其内部工作原理系列文章的第一篇。如果您对这类文章感兴趣,请关注我,也欢迎留言告诉我您感兴趣的数据结构。

文章来源:https://dev.to/jvanbruegge/what-does-big-o-notation-mean-anyway--1hea