我想知道是否有一种自动确定给定函数的大O时间复杂度(至少是粗略的)的方法?
如果我将O(n)函数与O(n log n)函数绘制在图表上,我认为我能够直观地确定哪一个是哪一个;我正在思考是否有某种启发式解决方案可以自动完成这个过程。
有什么想法吗?
编辑:我很高兴找到一种半自动化的解决方案,只是想知道是否有一种避免完全手动分析的方法。
我想知道是否有一种自动确定给定函数的大O时间复杂度(至少是粗略的)的方法?
如果我将O(n)函数与O(n log n)函数绘制在图表上,我认为我能够直观地确定哪一个是哪一个;我正在思考是否有某种启发式解决方案可以自动完成这个过程。
有什么想法吗?
编辑:我很高兴找到一种半自动化的解决方案,只是想知道是否有一种避免完全手动分析的方法。
big_O
库(链接在此处),它将执行时间的变化对独立变量n
进行拟合,以推断增长阶级O()
。Measuring .columns[::-1] complexity against rapid increase in # rows
--------------------------------------------------------------------------------
Big O() fits: Cubic: time = -0.017 + 0.00067*n^3
--------------------------------------------------------------------------------
Constant: time = 0.032 (res: 0.021)
Linear: time = -0.051 + 0.024*n (res: 0.011)
Quadratic: time = -0.026 + 0.0038*n^2 (res: 0.0077)
Cubic: time = -0.017 + 0.00067*n^3 (res: 0.0052)
Polynomial: time = -6.3 * x^1.5 (res: 6)
Logarithmic: time = -0.026 + 0.053*log(n) (res: 0.015)
Linearithmic: time = -0.024 + 0.012*n*log(n) (res: 0.0094)
Exponential: time = -7 * 0.66^n (res: 3.6)
--------------------------------------------------------------------------------
Jeffrey L Whitledge 是正确的。从停机问题的简单归约证明了这是不可判定的...
此外,如果我能编写这个程序,我会用它来解决 P vs NP 问题,并获得100万美元... B-)
我猜这不可能以完全自动化的方式实现,因为函数输入的类型和结构差异很大。
嗯,既然你无法证明一个函数是否会停止,我认为你要求有点过分了。
否则@Godeke已经解决了这个问题。
我不知道你在做这件事情的目的是什么,但我们在我教授的一门课程中遇到了类似的问题。学生们需要实现一个在特定复杂度下工作的东西。
为了不手动检查他们的解决方案并阅读他们的代码,我们使用了@Godeke建议的方法。目标是找到使用链表而不是平衡搜索树的学生,或者实现冒泡排序而不是堆排序的学生(即不符合所需复杂度的实现 - 但不必实际阅读他们的代码)。
令人惊讶的是,结果没有揭示出作弊的学生。这可能是因为我们的学生诚实并且想要学习(或者只是知道我们会检查这个;-))。如果输入很小,或者输入本身是有序的等等,就有可能错过作弊的学生。也有可能对没有作弊的学生产生误判,但尽管可能存在这些错误,它仍然非常值得,因为它可以节省大量的检查时间。
获取指示很容易(例如,“函数是线性的吗?亚线性的?多项式的?指数的?”)
找到确切的复杂度很难。
例如,这里有一个Python解决方案:您提供函数和创建其大小为N的参数的函数。您将获得要绘制或执行回归分析的(n,时间)值列表。它会计时一次以获得速度,要获得真正好的指示,需要多次计时以最小化环境因素的干扰(例如使用timeit模块)。
import time
def measure_run_time(func, args):
start = time.time()
func(*args)
return time.time() - start
def plot_times(func, generate_args, plot_sequence):
return [
(n, measure_run_time(func, generate_args(n+1)))
for n in plot_sequence
]
而要使用它来计时冒泡排序:
def bubble_sort(l):
for i in xrange(len(l)-1):
for j in xrange(len(l)-1-i):
if l[i+1] < l[i]:
l[i],l[i+1] = l[i+1],l[i]
import random
def gen_args_for_sort(list_length):
result = range(list_length) # list of 0..N-1
random.shuffle(result) # randomize order
# should return a tuple of arguments
return (result,)
# timing for N = 1000, 2000, ..., 5000
times = plot_times(bubble_sort, gen_args_for_sort, xrange(1000,6000,1000))
import pprint
pprint.pprint(times)
这是在我的机器上打印的:
[(1000, 0.078000068664550781),
(2000, 0.34400010108947754),
(3000, 0.7649998664855957),
(4000, 1.3440001010894775),
(5000, 2.1410000324249268)]