Python 3.x 关于递归二分法搜索的大O符号问题
我参加了麻省理工学院举办的Python课程(2016年秋季6.0001),在他的一次讲座中,教授描述了一个函数,如果元素(e)在列表(L)中,则返回Python 3.x 关于递归二分法搜索的大O符号问题,python-3.x,algorithm,recursion,big-o,Python 3.x,Algorithm,Recursion,Big O,我参加了麻省理工学院举办的Python课程(2016年秋季6.0001),在他的一次讲座中,教授描述了一个函数,如果元素(e)在列表(L)中,则返回True,否则返回False: def bisect_search1(L, e): if L == []: return False elif len(L) == 1: return L[0] == e else: half = len(L)//2
True
,否则返回False
:
def bisect_search1(L, e):
if L == []:
return False
elif len(L) == 1:
return L[0] == e
else:
half = len(L)//2
if L[half] > e:
return bisect_search1(L[:half], e)
else:
return bisect_search1(L[half:], e)
继续看下一张幻灯片,我知道对分搜索调用的复杂性为O(logn),因为每个循环或调用的输入都要减半
从幻灯片中我仍然不明白以下几点:
- O(n)对于复制列表的每个对分搜索调用,这是设置每个调用的成本,因此对每个递归级别执行此操作
- 如果我们真的很小心,请注意,要复制的列表的长度在每次递归调用时也会减半,结果表明,复制的总成本是O(n),这主要是由于递归调用导致的log n成本
切片列表所需的时间与切片的长度成比例。如果您有一个大小为n的列表,并且正在将其切片一半,则时间与n/2成正比,因此为O(n)
这位教授引用的关于复制成本占递归调用成本的主要部分的话只是说,通常二分搜索是O(logn)——递归调用的深度——但这里也有一些复制,其中一些需要O(n)时间。你可以用这些词来证明O(n logn)是一个上限,但它们不能证明精确的复杂性(实际上是O(n),因为每次复制的数量都是一半)。谢谢!。对于第二点,这是我的第一个想法,但是
half
变量使用整数除法(//),因此我不确定它是否真的是一个几何级数。@yfr整数除法引入的误差足够小,以至于它们不会改变大O。您可以使此计算更正式(更复杂)。例如,取N=比N大的2的下一次幂。然后你可以证明解是O(N/2+N/4+…)=O(N)=O(N)。谢谢你的详细解释!比方说,假设我没有将列表切成一半,而是复制了整个列表。这是否意味着O(n+n+n+…)=O(n),并且函数仍然是O(n logn)复杂度?@yfr如果在每个递归调用中执行n个步骤,其中n是原始列表大小,那么总数将是O(n logn)。但是如果执行n个步骤,其中n是传递给递归调用的列表的大小,它仍然是O(n)总计(我假设列表大小仍然以某种方式减少了一半,因为否则会有无限递归)。我想我现在更了解它了@保尔汉金的解释也让它更清楚。谢谢你们两个!