算法效率

计算机科学中，算法效率是算法的一种属性，算法效率与算法使用的计算资源量的大小有关。分析算法以确定其资源使用情况，即可根据不同资源的使用情况来衡量算法的效率。算法效率可以被认为类似于某个重复或持续过程的生产力大小。
为获得最大效率，一般希望能够尽量减少资源使用量。然而，时间复杂度和空间复杂度等不同的资源不能直接比较，因此通常两种算法中哪一种更有效率取决于哪种效率计量被认为是最重要的。
例如，冒泡排序和Timsort都是将一个列表中的每一项从小到大排序的排序算法。冒泡排序对列表进行排序的用时与元素数量平方成正比（ formula_1 ，参见大O符号），但只需要较少量的额外内存，该内存对于列表的长度来说是常数（ formula_2 )。 Timsort对列表排序的用时与列表长度呈对数关系（ formula_3 )，但空间用量与列表长度呈线性关系 ( formula_4 )。如果必须对给定应用程序的大型列表进行高速排序，则Timsort是更好的选择；但如果以内存占用最小化为重，那么冒泡排序更优。
背景.
爱达·勒芙蕾丝在 1843 年强调了效率相对于时间的重要性，并将其应用于查尔斯·巴贝奇的机械分析引擎：“在几乎每一个计算中，对于过程的连续性有各种各样的安排是可能的，并且为了计算引擎的目的，各种考虑必须影响它们之间的选择。一个基本目标是选择一种能够将完成计算所需的时间减少到最低限度的安排” 早期的电子计算机运算速度有限，随机存取存储器（内存）空间也有限。因此，发生了时空权衡。任务可以选择占用大量内存的快速算法，也可以选择使用少量内存的慢速算法。而后，工程权衡来在内存的限制内使用最快算法。
现代计算机比早期计算机要快得多，并且可用内存量更大（千兆字节，而不是以前的千字节）。尽管如此，Donald Knuth强调效率仍然是一个重要的考虑因素：“在已建立的工程学科中，可以轻易获得 12% 的改进，这样的改进从不被认为是微不足道的。我相信同样的观点应该在软件工程中占主导地位。” 
概述.
如果一个算法的资源消耗（也称为计算成本）处于或低于某个可接受的水平，则该算法被认为是有效的。粗略地说，“可接受”意味着：它将在可用计算机上的合理时间或空间内运行，“合理时间”和“空间”通常为关于输入数据大小的函数。自 1950 年代以来，计算机的可用计算能力和可用内存量都急剧增加，因此即使在 10 年前，当前可接受的水平也是不可接受的。事实上，由于摩尔定律，在现代智能手机和嵌入式系统上可以接受的效率的任务对于 10 年前的工业服务器来说可能效率低到无法接受。
计算机制造商经常推出性能更高的新型号。由于修改软件成本可能相当高，在某些情况下，获得更高性能的最简单和最便宜的方法可能是购买一台性能更高的计算机，前提是它与现有计算机兼容。
有很多方法可以衡量算法使用的资源，两个最常见的衡量标准是速度和内存使用情况。其他措施可能包括传输速度、临时磁盘使用、长期磁盘使用、功耗、总拥有成本、对外部刺激的响应时间等。许多这些措施取决于算法输入数据的大小，即要处理的数据量。它们还可能取决于数据的排列方式，例如，某些排序算法对已经排好序或以几乎全部按相反顺序排序的数据表现不佳。
在实践中，还有其他因素会影响算法的效率，例如对算法准确性、可靠性的要求。如下文所述，算法的实现方式也会对实际效率产生重大影响，尽管这在许多方面都与优化问题有关。
理论分析.
下面是应用于渐近算法时间复杂度的大 O 符号的一些示例：
基准测试：衡量性能.
对于新版本的软件或提供与竞争系统的比较，有时会使用基准测试，这有助于衡量算法的相对性能。例如，如果产生了一种新的排序算法，则可以将其与其前身进行比较，以确保它至少与以前一样有效地处理已知数据，同时考虑到任何功能改进。客户在比较替代供应商的各种产品时可以使用基准来估计哪种产品在功能和性能方面最适合他们的特定要求。例如在大型计算机领域， Syncsort等独立软件公司的某些专有分类产品与IBM等主要供应商的产品竞争效率。
一些基准测试提供了比较分析各种编译和解释语言的相对速度的机会 计算机语言基准游戏比较了几种编程语言中典型编程问题的实现性能。
使用各种用户指定的标准，DIY基准测试也可以展示不同编程语言的相对性能。这很简单，正如 "Christopher W. Cowell-Shah" 的“九种语言性能综述”通过示例演示的那样。 
算法实现对效率的影响.
算法的实现方法也可能对效率产生影响，例如编程语言的选择，算法实际编写的方式， 特定语言选择的特定编译器，编译时使用的编译选项，甚至正在使用的操作系统。在许多情况下，由解释器实现的语言（解释语言）可能比由编译器实现的语言（编译语言）慢得多。 请参阅有关即时编译和解释语言的文章。
还有其他因素可能会影响时间或空间效率，但这些因素可能超出程序员所能控制的范围，例如数据结构对齐、数据颗粒度、访问局部性、快取一致性、垃圾回收（GC）、指令层级并行、多线程（硬件或软件级别）、同时多线程处理和子程序的调用。 
一些处理器具有向量处理能力，允许单指令流多数据流操作；也许程序员或编译器可以轻易使用这些功能，但也有可能不可以。为顺序处理设计的算法可能需要被完全重构来利用并行计算，或者它们可以很容易地重新配置。随着并行计算和分布式计算在 2010 年代后期变得越来越重要，并行和分布式计算系统（如CUDA 、 TensorFlow 、 Hadoop 、 OpenMP和MPI ）的高效高级API被越来越多地投资。
编程中可能出现的另一个问题是与相同指令集（例如x86-64或ARM ）兼容的处理器可能以不同的方式实现指令，因此在某些架构上相对较快的指令在其他架构上可能相对较慢.这通常会给优化编译器带来挑战，编译器必须对编译目标平台上可用的特定CPU和其他硬件有大量了解，才能最好地优化程序的性能。在极端情况下，编译器可能被迫模拟目标平台不支持的指令，迫使它生成代码或链接外部库调用以产生在该目标平台上无法计算的结果，即使它是编译平台上是支持的，在其他平台上的硬件效率更高。在浮点运算的嵌入式系统中经常出现这种情况，其中单片机通常缺乏对浮点运算的硬件支持，因此需要计算昂贵的软件例程来产生浮点计算。
资源使用量的测量.
度量通常表示为输入大小的函数formula_5 .
最常见的两种测量方法是：
对于由电池供电的计算机（例如笔记本电脑和智能手机），或用于非常长时间或大量计算的计算机（例如超级计算机），其他感兴趣的度量是：
，从嵌入式物联网设备到单片机再到服务器农场，功耗正在成为所有类型和所有规模的计算任务的重要指标。 这种趋势通常被称为绿色计算。
在某些情况下，不太常见的计算效率度量也可能是相关的：
时间.
理论.
分析算法，通常使用时间复杂度分析来估计运行时间作为输入数据大小的函数。结果通常使用大 O 表示法表示。这对于比较算法很有用，尤其是在要处理大量数据时。当数据量较小时，需要更详细的估计来比较算法的性能，尽管这可能不太重要。包含并行处理的算法可能更难分析。
实践.
使用基准来计时算法的使用。许多编程语言都有提供CPU 时间使用的可用功能。对于长时间运行的算法，经过的时间也可能很重要。结果通常应在几次测试中取平均值。
基于运行的分析对硬件配置以及在多处理和多编程环境中同时运行的其他程序或任务的可能性非常敏感。
这种测试还很大程度上取决于特定编程语言、编译器和编译器选项的选择，因此被比较的算法必须都在相同的条件下实现。
空间.
本节涉及执行算法时内存资源（寄存器、缓存、 RAM 、虚拟内存、辅助内存）的使用。至于上面的时间分析，分析算法，通常使用空间复杂度分析来估计所需的运行时内存，作为输入数据大小的函数。结果通常使用大 O 表示法表示。
内存使用最多有四个方面需要考虑：
早期的电子计算机和家用计算机的工作内存量相对较少。例如，1949 年的电子延迟存储自动计算器（EDSAC）的最大工作内存为 1024 个 17 位字，而 1980 年的 Sinclair ZX80起初具有 1024 个 8 位字节的工作内存。在 2010 年代后期，个人电脑通常具有 4 到 32 GB的内存，这增加了 3 亿多倍。
缓存和内存层次结构.
当前的计算机可能具有相对较大的内存量（可能是千兆字节），因此将算法压缩到有限的内存量中的问题比过去要小得多。但是下列四种不同类型的内存可能很重要：
内存需求将适合高速缓存内存的算法将比适合主内存的算法快得多，而主内存又将比必须求助于虚拟内存的算法快得多。正因为如此，缓存替换策略对于高性能计算极其重要，缓存感知编程和数据对齐也是如此。使问题进一步复杂化的是，一些系统具有多达三个级别的高速缓存，具有不同的有效速度。不同的系统将有不同数量的这些不同类型的内存，因此算法内存需求的影响可能因系统而异。
在电子计算的早期，如果一个算法及其数据不适合主存储器，那么该算法就无法使用。如今，虚拟内存的使用似乎提供了很多内存，但以性能为代价。如果一个算法及其数据适合缓存，那么可以获得非常高的速度；在这种情况下，最小化空间也有助于最小化时间。这称为局部性原理，可细分为参考局部性、空间局部性和时间局部性。不完全适合高速缓存但表现出引用局部性的算法可能会执行得相当好。
对编程现状的批评.
“软件效率每 18 个月减半，以补偿摩尔定律。”
“在移动平台中，将执行的指令减半可以使电池寿命加倍，巨大的数据量将为更好的软件和算法带来巨大机会：当 formula_6 很大时，将操作数从 formula_7 减少到formula_8具有显著效果…当N=300亿时，这种变化相当于 50 年的技术改进。”
最佳算法竞赛.
以下比赛根据由评委决定的一些任意标准邀请最佳算法参赛：