Python 使用BigΘ的运行时间;符号
有人能给我解释一下如何用大Θ符号来确定这些设备的运行时间吗?我读了很多东西,但仍然不知道从哪里开始 在Python 使用BigΘ的运行时间;符号,python,algorithm,analysis,Python,Algorithm,Analysis,有人能给我解释一下如何用大Θ符号来确定这些设备的运行时间吗?我读了很多东西,但仍然不知道从哪里开始 在filter中,我认为它是Θ(n^2),因为它使用谓词函数f和n个递归调用来检查大小为n的列表中的每个元素 revfilter_beta看起来非常相似,只是在过滤时反转,所以这不也是Θ(n^2)吗 revfilter_alpha会过滤一个反向,所以这不是n^2*n^2=Θ(n^4)吗 有人有什么想法吗?filter有n递归调用,但你也会在每次迭代中执行一个复制操作,这需要n,因此你最终得到了Θ(
filter
中,我认为它是Θ(n^2),因为它使用谓词函数f和n个递归调用来检查大小为n的列表中的每个元素
revfilter_beta
看起来非常相似,只是在过滤时反转,所以这不也是Θ(n^2)吗
revfilter_alpha
会过滤一个反向,所以这不是n^2*n^2=Θ(n^4)吗
有人有什么想法吗?
filter
有n
递归调用,但你也会在每次迭代中执行一个复制操作,这需要n
,因此你最终得到了Θ(n^2)。如果您“正确”地实现了它,那么它应该是Θ(n)
同样适用于my\u reverse
同样适用于revfilter\u beta
revfilter_alpha
只做一个filter
然后一个reverse
,这样sΘ(n^2+n^2)=Θ(n^2)
编辑:让我们进一步了解一下
过滤器
您想要了解的是相对于输入的大小执行了多少操作O(n)
意味着在最坏的情况下,您将按照n
操作的顺序进行操作。我说“按顺序”是因为你可以,例如,做O(n/2)
操作,或者O(4n)
,但最重要的因素是n
。也就是说,随着n
的增长,常数因子变得越来越不重要,因此我们只看非常数因子(n
)
那么,filter
对大小n
的列表执行多少操作
让我们从头开始。如果n
为0-空列表怎么办?然后它将返回一个空列表。假设这是一次手术
如果n
为1怎么办?它将检查是否应包括lst[0]
——该检查需要多长时间才能调用f
——然后它将复制列表的其余部分,并对该副本执行递归调用,在本例中,该副本为空列表。因此filter(1)
需要f+copy(0)+filter(0)
操作,其中copy(n)
是复制列表所需的时间,而f
是检查是否应包含元素所需的时间,假设每个元素所需的时间相同
过滤器(2)
怎么样?它将执行1次检查,然后复制列表的其余部分,并对其余部分调用filter
:f+copy(1)+filter(1)
你已经可以看到这个模式了<代码>过滤器(n)
采用1+拷贝(n-1)+过滤器(n-1)
现在,copy(n)
只是n
——以这种方式对列表进行切片需要n
操作。因此我们可以进一步简化:filter(n)=f+n-1+filter(n-1)
现在,您可以尝试将过滤器(n-1)展开几次,看看会发生什么:
def filter(f, lst):
if lst == []: return []
if f(lst[0]): return [lst[0]] + filter(f, lst[1:])
return filter(f, lst[1:])
def my_reverse(lst): # Reverse the list
def reverse_helper(x,y):
if x == []: return y
return reverse_helper(x[1:], [x[0]] + y)
return reverse_helper(lst, [])
def revfilter_alpha(f, lst): # Reverse and filter ...
return my_reverse(filter(f, lst))
def revfilter_beta(f, lst): # Reverse and filter ...
if lst == []: return []
return revfilter_beta(f, lst[1:]) + ([lst[0]] if f(lst[0]) else [])
我们能概括出x
重复吗?那1,3,6,10,15
。。。序列是三角形数字-即,1
,1+2
,1+2+3
,1+2+3+4
,等等。从1
到x
的所有数字之和是x*(x-1)/2
filter(n) = f + n-1 + filter(n-1)
= 1 + n-1 + (f + n-2 + filter(n-2))
= f + n-1 + f + n-2 + filter(n-2)
= 2f + 2n-3 + filter(n-2)
= 2f + 2n-3 + (f + n-3 + filter(n-3))
= 3f + 3n-6 + filter(n-3)
= 3f + 3n-6 + (f + n-4 + filter(n-4))
= 4f + 4n-10 + filter(n-4)
= 5f + 5n-15 + filter(n-5)
...
现在,什么是x
?我们要重复多少次?好的,您可以看到当x
=n
时,您不再有递归-过滤器(n-n)
=过滤器(0)
=1
。我们的公式是:
= x*f + x*n - x*(x-1)/2 + filter(n-x)
我们可以进一步简化:
filter(n) = n*f + n*n - n*(n-1)/2 + 1
因此,你有它-一个相当详细的分析。那将是((1/2)n^2+(f+1/2)n+1)。。。假设f
是不重要的(比如f
=1),它会到达Θ((1/2)n^2+(3/2)n+1)
现在你会注意到,如果copy(n)
花费了一个恒定的时间量而不是一个线性的时间量(如果copy(n)
是1而不是n
),那么你就不会得到这个n^2
项
我承认,当我最初说Θ(n^2)
时,我并不是在脑子里想出来的。相反,我想:好吧,你有n
递归步骤,由于复制
,每个步骤都需要n
时间<代码>n*n=n^2,因此Θ(n^2)
。更准确地说,n
在每一步都会收缩,所以实际上有n+(n-1)+(n-2)+(n-3)+……+1
,其结果与上面的数字相同:n*n-(1+2+3+…+n)
=n*n-n*(n-1)/2
=(1/2)n^2+(1/2)n
,如果我使用了上面的0
而不是f
,这是相同的。同样,如果您有n
步骤,但每个步骤都是1
而不是n
(如果您不必复制列表),那么您就有1+1+1+…+1
,n
次,或者干脆n
但是,这需要更多的直觉,所以我想我也会向你展示蛮力方法,你可以应用于任何事情 您的所有函数都是
O(N^2)
,因为它们每个递归步骤花费O(N)
时间,并且在长度N
列表上会有N
步骤
在函数中有两个昂贵的操作(即,O(N)
)。第一种是切片(例如lst[1://code>)。第二种是列表连接(使用+
运算符)
这两种方法的成本都可能比您预期的要高,这主要是因为Python的列表与其他语言中的列表数据类型不同。在引擎盖下,它们是数组,而不是链表。可以在O(1)时间内对链表执行上述操作(尽管O(1)
切片具有破坏性)。例如,在Lisp中,您使用的算法
filter(n) = n*f + n^2 - (n^2 - n)/2 + 1
= n*f + n^2 - n^2/2 + n/2 + 1
= n^2 - n^2/2 + f*n + n/2 + 1
= (1/2)n^2 + (f + 1/2)n + 1
def my_filter(f, iterable):
for e in iterable:
if f(e):
yield e
def my_reversed(iterable):
storage = list(iterable) # consumes all the input!
for i in range(len(storage)-1, -1, -1):
yield storage[i]