Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么这两个功能之间的速度差异如此之大?_Python_Function_Performance - Fatal编程技术网

Python 为什么这两个功能之间的速度差异如此之大?

Python 为什么这两个功能之间的速度差异如此之大?,python,function,performance,Python,Function,Performance,我一直在阅读麻省理工学院的一些开放式课件问答,他们有一个问题是这样的: 6)考虑下面所用的两个函数,用来玩“猜数字游戏”。 以下是老师提供的答题纸: def findNumber(maxVal): """ Assumes that maxVal is a positive integer. Returns a number, num, such that cmpGuess(num) == 0 """ s = range(0, maxVal) return bsea

我一直在阅读麻省理工学院的一些开放式课件问答,他们有一个问题是这样的:

6)考虑下面所用的两个函数,用来玩“猜数字游戏”。 以下是老师提供的答题纸:

def findNumber(maxVal): 
    """ Assumes that maxVal is a positive integer. Returns a number, num, such that cmpGuess(num) == 0 """ 
    s = range(0, maxVal) 
    return bsearch(s, 0, len(s) -1)

def bsearch(s, first, last): 
    if (last-first) < 2: 
        if cmp(s[first]) == 0: 
            return first 
    else:
        return last

    mid = first + (last -first)/2
    if cmp(s[mid]) == 0:
        return s[mid]
    if cmp(s[mid]) == -1:
        return bsearch(s, first, mid -1)
    return bsearch(s, mid + 1, last)
我的跑步时间:0.000621605333677s 教师跑步时间:29.627s

这不可能是对的。我连续计时了好几次,在所有情况下,第二个函数的结果都是荒谬的30秒。我直接从MIT提供的文档中复制粘贴了解决方案函数。有什么想法吗

我现在还没有安装Python,所以从一看可能是因为老师使用了递归(在b搜索中)?

我能看到的最明显的事情是,每次调用老师的函数时,它都会创建一个包含1000000个整数的列表(假设Python 2.x),然后当它返回时,它会再次销毁该列表


这需要一段时间。

让我以回答的形式重复我的评论:
range(maxval)
分配整个列表,因此教师的算法具有
Θ(maxval)
空间复杂度,因此
Θ(maxval)
时间复杂度(创建这样的列表需要时间)。因此,教师的解决方案 具有“尽可能低的时间复杂度”

当使用
xrange(maxval)
时,将不再分配整个列表。您和老师的解决方案都具有时间复杂性


此外,您的解决方案具有
Θ(1)
空间复杂度,而(优化)教师的解决方案具有
Θ(log(maxval))
空间复杂度-递归调用消耗堆栈内存。

教师的版本有三个问题,所有这些问题都已在OP的版本中修复

  • s=range(maxVal)
    在Python 2中创建一个列表。使用xrange()可以节省创建和销毁列表的时间。然而,使用s的整个想法都是胡说八道,因为对于所有相关的i,
    s[i]==i
    ,因此s可以被扔掉,省去了查找

  • 递归:递归深度是关于math.log(1000000.0,2.0)。。。大约20岁。因此,每个findNumber()调用大约有20个函数调用,与跳回while循环的开始相比,函数调用非常昂贵

  • 它每次猜测调用
    cmp(s[mid])
    两次,而不是一次,因此每次调用findNumber()又浪费了20次函数调用


  • 您说您测试了两个脚本以确保它们给出相同的答案,但它们没有。正如您编写的那样,教师脚本将始终返回最后一个元素。这是因为以下几行:

    def bsearch(s, first, last): 
        if (last-first) < 2: 
            if cmp(s[first]) == 0: 
                return first 
        else:
            return last
    

    这并不是真正解决缓慢问题的答案,这显然是(正如已经指出的)由于O(N)内存的分配(这是一个大内存)、递归、列表查找、每次bsearch调用可能调用cmp两次而不是一次并存储结果,以及必须显式检查是否
    (last-first)<2
    用于每次调用
    b搜索
    ,因为他使用的变量
    last
    包含在可能值的范围内,而不是比可能的最高值多1。顺便说一下,通过更改行,您自己的代码可以稍微快一点:

                floor = med
    


    因此,您将med排除在搜索范围之外。您已经知道它不是基于cmp结果的值。顺便说一句,我不会使用
    cmp
    作为我自己的函数名,因为它是Python内置函数(我知道它在规范中是
    cmpGuess

    第一个问题(我假设您先检查了它,但让我们确定一下):两者都给出了正确的答案吗?俗话说:如果它不一定是正确的,我可以把它降到0。
    s=range(0,maxVal)
    ???老师的解决方案需要
    O(maxval)
    space。是的,两者都是正确的,一个比另一个慢几个数量级。@阿比纳夫:第二个建议是否定的,
    len
    在列表(以及大多数其他集合和序列,包括dicts、set和string)上是O(1).我无法使用
    time.time()
    为教师版本重现较长的时间。你能测试一下吗?您还可以检查您是否正在交换吗?这可以解释明显的减速或超过了最大递归深度
    ,但不是47662x减速。@delnan:最大递归深度是关于math.log(1000000.0,2.0)。。。大约20。啊,是的,那确实需要一段时间。完全忘记了
    range
    创建一个列表(Python3
    range
    创建了一个智能迭代器,它甚至提供了-便宜的,因为它很聪明,可以从参数-索引计算第n项)。您可以在早期版本的Python中使用xrange惰性地生成迭代器。事实上,有没有不使用xrange的理由?@pisswillis,是的,但不经常。例如,您不能对xrange(或Python 3.x中的
    range
    )进行切片。只是想知道,您是否参加了该课程,或者是否也在学习开放式课程?不,我以前没有参加过该课程,也没有在OCW上看过,但我看过其他一些课程。当我注意到第一个错误(缩进)时,我决定看看原始解决方案。我给开放式课程发了一封关于这些问题的电子邮件,希望解决方案能够得到纠正。
    def cmp(guess):
        if guess > num:
            return 1
        elif guess < num:
            return -1
        else: return 0
    
    t = timeit.Timer('find(1000000)', 'from __main__ import find,cmp')
    t1 = timeit.Timer('findNumber(1000000)', 'from __main__ import findNumber,bsearch')
    print str(t.timeit(1000))
    print str(t1.timeit(1000))
    
    def bsearch(s, first, last): 
        if (last-first) < 2: 
            if cmp(s[first]) == 0: 
                return first 
        else:
            return last
    
    def bsearch(s, first, last): 
        if (last-first) < 2: 
            if cmp(s[first]) == 0: 
                return first 
            else:
                return last
    
        if cmp(s[mid]) == -1:
    
        if cmp(s[mid]) == 1:
    
                floor = med
    
                floor = med + 1