大 O 复杂度表示法 - 数据结构训练营

大 O 复杂度表示法是一种粗略衡量算法性能的方法,以便在讨论算法时进行比较。 大 O 复杂度表示法表示代码(消耗时间/占用空间)随数据规模增长的变化趋势: 时间复杂度的全称是渐进时间复杂度,表示算法的执行时间与数据规模之间的增长关系。 空间复杂度全称就是渐进空间复杂度,表示算法的存储空间与数据规模之间的增长关系。 之所以分别衡量时间和空间,是因为可能一种算法执行的操作比另一种算法少,但它却占用更多的内存。 所以需要根据不同的要求来选择不同的算法。 下面是一些常见的复杂度: | 名字 | 复杂度 | 感受 | |--|--|--| | 常数复杂度 | O(1) | 了不起 | | 对数复杂度 | O(log N) | 很棒 | | 线性复杂度 | O(N) | 还好 | | 线性对数复杂度 | O(N log N) | 呵呵 | | 次方复杂度 | O(N ^ 2) | 狗屎 | | 指数复杂度 | O(2 ^ N) | 可怕 | | 阶乘复杂度 | O(N!) | 可以骂人吗 | 为了让你对这些的操作数量级有更直观的认识。来看看指定 N,这些复杂度计算出来的值是多少。 | | N = 5 | 10 | 20 | 30 | |--|--|--|--|--| | O(1) | 1 | 1 | 1 | 1 | | O(log N) | 2.3219... | 3.3219... | 4.3219... | 4.9068... | | O(N) | 5 | 10 | 20 | 30 | | O(N log N) | 11.609... | 33.219... | 84.638... | 147.204... | | O(N ^ 2) | 25 | 100 | 400 | 900 | | O(2 ^ N) | 32 | 1024 | 1,048,576 | 1,073,741,824 | | O(N!) | 120 | 3,628,800 | 2,432,902,0... | 265,252,859,812,191,058,636,308,480,000,000 | O(1) O(log N) O(N) O(N log N) O(N ^ 2) O(2 ^ N) O(N!) 看到了吧,即使对于相对较小的数据集,也会做大量的额外工作。 对于数据结构,通常会执行如下 4 种类型的操作:访问、搜索、插入和删除。 需要注意的是,一种数据结构可能擅长一种操作,另一种操作却很糟。 | | 访问 | 搜索 | 插入 | 删除 | |--|--|--|--|--| | 数组 | O(1) | O(N) | O(N) | O(N) | | 链表 | O(N) | O(N) | O(1) | O(1) | | 二叉搜索树 | O(log N) | O(log N) | O(log N) | O(log N) | 直观感受是 | | 访问 | 搜索 | 插入 | 删除 | |--|--|--|--|--| | 数组 | 了不起 | 还好 | 还好 | 还好 | | 链表 | 还好 | 还好 | 了不起 | 了不起 | | 二叉搜索树 | 很棒 | 很棒 | 很棒 | 很棒 | 更进一步,某些操作将具有不同的平均性能和最坏情况性能。 没有完美的数据结构,可以根据正在使用的数据以及将使用它做的事情来做选择。 这就是为什么了解许多不同的常见数据结构很重要的原因,可以做出更好的选择。
使用正确的数据结构可以大大简化原本复杂的逻辑。如果很注重性能或想节约内存,那么就需要选择正确的数据结构。来和我一起用 JavaScript 语言来实现一些常用数据结构吧。


运行