Python 寻找函数的转折点

Python 寻找函数的转折点,python,algorithm,binary-search,Python,Algorithm,Binary Search,我想要为我的函数输出True的第一个值。我目前有一个搜索,工作良好,但我认为仍然有点效率低。谁能推荐一个更好的二进制搜索?我的代码如下,简化了 guess = 2 limits = [2, 2**35] #The search area while True: if myFunction(guess) == False: limits[0] = max(limits[0], guess) #Limit the search area guess *= 2

我想要为我的函数输出
True
的第一个值。我目前有一个搜索,工作良好,但我认为仍然有点效率低。谁能推荐一个更好的二进制搜索?我的代码如下,简化了

guess = 2
limits = [2, 2**35] #The search area

while True:
    if myFunction(guess) == False:
        limits[0] = max(limits[0], guess) #Limit the search area
        guess *= 2
    else:
        limits[1] = min(limits[1], guess) #Limit the search area
        guess = int((limits[0] + limits[1])/2) #The guess is the midpoint of the search area
        if myFunction(guess) == True and myFunction(guess-1) == False:
            return guess

这是寻找单调递增或递减函数平交的经典问题。正如你所猜测的,这是可以通过。您的代码有一些bug,这并不奇怪:

虽然这个想法很简单,但正确实现二进制搜索需要注意其退出条件和中点计算的一些微妙之处

因此,在可能的情况下,您应该避免编写自己的二进制搜索。幸运的是,Python提供了一个库模块,可以为您完成这项工作

from bisect import bisect_left

MIN = 2
MAX = 2**35

def search(f):
   # Finds the first position of `True` in `f`
   return bisect_left(f, True, lo=MIN, hi=MAX + 1)
不要被
bisect
仅适用于可索引对象的事实所迷惑:不需要创建包含
2**35
元素的列表。您可以使用生成器对象,而不是使用
\uu getitem\uu
语法。为此,将函数封装在一个类中,并定义getter方法,该方法将为感兴趣点左侧的所有参数值返回
False
,否则返回
True

def myFunction1(index):
   return index >= 1456
def myFunction2(index):
   return index >= 2
def myFunction3(index):
   return index >= MAX - 1

class F:
   def __init__(self, f):
      self.f = f
   def __getitem__(self, index):
      return self.f(index)

# testing code
print(search(F(myFunction1))) # prints 1456
print(search(F(myFunction2))) # prints 2
print(search(F(myFunction3))) # prints MAX - 1

你说的“第一”是什么意思?范围内的任何元素符合您的标准?还是最小的?是的,最小的。因此,没有理由在范围的中间进行猜测,对吗?如果您希望范围内的第一个值满足您的条件,那么您只需编写
next((如果myFunction(x)),则为myu范围内的x,无)
。如果这不是您需要的,请告诉我们。@RayToal我对这个问题的解释(我承认可能是错误的)是
myFunction
对于
x
小于某个数
N
的值返回False,对于
x
大于或等于
N
的所有值返回True。目标是找到
N
。因此,在调用
myFunction
不超过35次时,可以使用二进制搜索来查找
N
。但是
next
将进行线性搜索,可以调用
myFunction
多达340亿次。不用担心,我没有花足够的时间阅读它。很好。不过,我认为你不能比二进制搜索做得更好。从中间开始,走一条路或另一条路。与最简单的二进制搜索相比,即使知道转折点是更接近开始还是结束也不会带来太多好处,因为2**35的搜索空间只需要35个探测。我从未使用过Python类。这可以不用上课吗?如果不是,我如何在类中定义我的函数?我该如何调用该函数——比如说它的名字是myFunction?对不起,我在这方面完全是个傻瓜。我更改了示例,以便分别定义
myFunction
的示例-希望这能让它更清楚。为了实现这一点,我怀疑您可能必须使用一个类:它只是一种欺骗解释器接受它的方法。如果您不想使用它,您可以搜索二进制搜索的Python实现,并复制粘贴其中一个:有很多,甚至是堆栈溢出。我成功了。谢谢你,伙计!我遇到的唯一问题是在尝试2^35之类的值时系统的最大int大小,但在其他方面这非常方便!