繁体   English   中英

如果我的函数有两个嵌套的 for 循环,它是否以二次时间运行?

[英]If my function has two nested for loops does it run in quadratic time?

我正在学习用 Big-O 符号分析算法。 我正在研究Python 教科书中Ranum & Miller 的问题解决算法 其中一项任务如下:

编写两个 Python 函数来查找列表中的最小值。 第一个函数应该将每个数字与列表中的每个其他数字进行比较。 𝑂(𝑛2)。 第二个函数应该是线性的𝑂(𝑛)。

没有指导或解决方案,所以我盲目地去。 这些分别是我对二次函数和线性函数的解决方案:

def find_min_quadratic(a_list):
    min_number = aList[0]
    for a_number in a_list:
        for item in range(len(a_list)):
            if min_number > a_number:
                min_number = a_number
    return min_number


def find_min_linear(a_list):
    return min(a_list)

我的逻辑是有两个嵌套 for 循环迭代问题a_list ,所以这会给我 O(n^2) 运行时间。 而对于第二个解决方案,我只是调用内置函数min()以便应该具有线性时间? (虽然现在我认为这可能意味着它有固定的时间?)谁能帮我看看我是否正确地实施了这个或者我是否遗漏了什么?

我最初将作业误读为“在列表中查找最大数”,因此我也为max_number.编写了这些函数max_number. 我遵循与min_number.相同的逻辑min_number. 与上述相同的问题,我对二次和线性时间的理解和实现是否正确?

def find_max_quadratic(a_list):
    max_number = None
    for a_number in a_list:
        for item in range(len(a_list)):
            if a_number > a_list[item]:
                max_number = a_number
    return max_number


def find_max_linear(a_list):
    return max(a_list)


你的逻辑是正确的,你分析你自己实现的方法的方式正是它应该如何完成的。

可能令人困惑的是第二个,在这种情况下,您正在调用某个函数,该函数已在语言库本身中实现。 这也有自己的复杂性,在这种情况下是 O(n)。

如果您想制作具有线性复杂度的自己的方法,那么您可以通过以下方式实现它:

  1. 定义最小变量
  2. 循环遍历数组并将循环中的值与定义的最小值进行比较
  3. 如果 min > 循环值,则将其重新分配给 min

您分析和计算算法复杂性的逻辑是正确的。 但是,我怀疑您的老师可能对您编写的代码不满意。

你的线性函数有问题

def find_min_linear(a_list):
    return min(a_list)

您被要求编写一个返回列表最小值的函数,为此,您...使用了返回列表最小值的 python 内置函数。

对于任何实际应用程序来说,这都是一个好主意,因为 python 内置函数可能比您自己编写的任何函数都快; 并且您可以相信它没有错误,而不是浪费时间检查您自己的代码是否存在错误。

但是你的老师可能对你想出一个算法来找到最小值更感兴趣,而不是你知道已经有一个 python 内置函数可以做到这一点。 min函数确实是线性的,但这个函数之所以存在,只是因为有人能够首先提出一个线性算法,并用它来实现函数。 事实上,我觉得很令人不安的是,你的老师没有明确禁止你在这个作业中使用 python 内置的minmax 如果我是学生,我可能会提到内置函数存在并在线性时间内执行,然后我会编写自己的函数而不使用现有函数。

你的二次函数有问题

def find_min_quadratic(a_list):
    min_number = aList[0]
    for a_number in a_list:
        for item in range(len(a_list)):
            if min_number > a_number:
                min_number = a_number
    return min_number

从技术上讲,您的函数有效,并且是二次的。 然而,内部的 for 循环令人不安。 变量item从未使用过; 它的唯一目的是确保循环有n次迭代(其中n是列表的长度)。 循环体将始终执行完全相同; if的条件要么始终为真,要么始终为假; 如果它是真的,那么min_number = a_number只会min_number = a_number将相同的值写入相同的变量。

换句话说:在 for 循环中重复执行这个if语句是没有意义的; 只需执行一次。

def find_min_quadratic(a_list):
    min_number = aList[0]
    for a_number in a_list:
    #    for item in range(len(a_list)):
            if min_number > a_number:
                min_number = a_number
    return min_number

多啊啊啊! 只需少一行,算法仍然正确执行并返回列表中的最小值。

该算法现在是线性的,而不是二次的。 你的老师问你一个二次算法。 您可能认为添加一个 for 循环来使您的算法成为二次型是可以的。 这在技术上是正确的,但以下算法也适用:

def find_min_quadratic(a_list):
    min_number = find_min_linear(a_list)
    for item in range(len(a_list)**2):
        beebboop = 57
    return min_number

毫无疑问,这个函数是二次的——我们明确地包含了一个运行n^2次迭代的循环。 但是你的老师可能会觉得你在取笑他们。

此外,如果您仔细阅读,您的作业文本会说“第一个函数应该将每个数字与列表中的每个其他数字进行比较。”。 你的二次函数没有这样做。

二次算法

您已经找到了一个线性算法(通过从二次函数中删除一行),所以现在您仍然需要找到一个二次函数。 这有点违反直觉,我个人非常不喜欢这个任务。 编写算法通常遵循以下步骤:

  1. 表达问题
  2. 找到解决问题的算法
  3. 分析算法的复杂性
  4. 找到一种新算法来解决问题的复杂度较低

因此,沿着这些方向进行分配将很有意义:

  1. 编写一个函数来查找列表的最小值
  2. 分析函数的复杂性
  3. 如果您的函数不是线性的,则编写一个新函数以在线性时间内找到列表的最小值。

如果您已经找到了线性函数,那么寻找一个效率较低的函数是很尴尬的,这导致您添加了一个无缘无故浪费时间的 for 循环。

我认为分配的重点不是人为地制作一个效率较低的函数,而是尝试提出一种完全不同的算法,然后了解并非所有算法都具有同等效率。

你的老师明确说“第一个函数应该将每个数字与列表中的每个其他数字进行比较。”。 所以我们可以用它来编写一个新函数:

def find_min_quadratic(a_list):
    # ...
    for a in a_list:
        # ...
        for b in a_list:
            if a > b:
                # ...
        # ...

尝试填空,以便返回最小值。 您可以添加其他变量,您可以添加其他if语句,但不要添加其他 for 循环。 提示:如何判断元素a是否为最小值? 由于for b in a_list循环中的for b in a_list我们可以找到a是否是最小值吗?

二次解如下:

def findMinQuad(aList):
    overallmin = alist[0]
    for i in aList:
        issmallest = True 
        for j in a List: 
            if i > j:
                issmallest = False
        if issmallest: 
                overallmin = i 

    return overallmin

由于我们使用嵌套的 for 循环对输入 aList 迭代两次,我们知道答案是二次时间 O(n^2)。 嵌套循环还确保我们将每个数字与列表中的每个其他数字进行比较。

线性解决方案如下:

def findMinLin(aList):
    minsofar = aList[0]
    for i in aList:
        if i < minsofar:
            minsofar = i
    return minsofar

这个不言自明,我们只是假设第一个数字是最小值,然后我们遍历列表以查看是否找到较小的数字。 如果我们这样做,那么该数字就是新的最小数字,在循环结束时,保存为最小数字的任何数字实际上都是最小的数字。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM