【问题标题】:Is the big O runtime of my function N^2 or N log N?我的函数的大 O 运行时间是 N^2 还是 N log N?
【发布时间】:2019-11-21 15:19:06
【问题描述】:
from linkedlist import LinkedList

def find_max(linked_list): #  Complexity: O(N)
  current = linked_list.get_head_node()
  maximum = current.get_value()
  while current.get_next_node():
    current = current.get_next_node()
    val = current.get_value()
    if val > maximum:
      maximum = val
  return maximum

def sort_linked_list(linked_list):  # <----- WHAT IS THE COMPLEXITY OF THIS FUNCTION?
  print("\n---------------------------")
  print("The original linked list is:\n{0}".format(linked_list.stringify_list()))
  new_linked_list = LinkedList()

  while linked_list.head_node:
    max_value = find_max(linked_list)
    print(max_value)
    new_linked_list.insert_beginning(max_value)
    linked_list.remove_node(max_value)

  return new_linked_list

由于我们循环了while循环N次,运行时间至少为N。对于每个循环我们调用find_max,但是,对于每次调用find_max,我们解析为find_max的linked_list减少了一个元素。基于此,运行时不是N log N吗?

还是N^2

【问题讨论】:

  • 什么是 1 + 2 + ... + (n-1) + n?
  • 不,你还是 N^2。每次减少列表的大小意味着你是 1/2 N^2,但这只是一个常数。

标签: python python-3.x big-o complexity-theory


【解决方案1】:

还是O(n²);每次将大小减小 1 只会使n * n / 2 有效工作(因为平均而言,每次通过时您必须处理原始长度的一半,而您仍在进行n 传递)。但由于常量因子不包含在大 O 表示法中,因此简化为 O(n²)

要成为O(n log n),每一步都必须减半要扫描的列表大小,而不是简单地减少一。

【讨论】:

  • 谢谢,我特别喜欢你上一条关于运行时间为 O(n log n) 时的评论,这确实清除了很多!
  • 注意:我写了n * n / 2,而技术上它是n * (n + 1) / 2。但是加法比这里的常数除数更重要,当我谈到在每次传球时平均处理原始长度的一半时,省略它会更清楚。
  • @xingZì:很高兴它有帮助。我会注意到,从技术上讲,它不必专门将大小减半。减半会给你一个以 2 为底的日志,这通常是人们在讨论复杂性时的意思(因为分而治之通常是通过每一步减半自然完成的)。从技术上讲,任何在每一步之后应用固定除数的方法(例如,将长度减少三分之一、四分之一或三分之二等)都是O(n log n) 的一种形式,但在 99% 的情况下,人们提到的日志是base-2,它指的是涉及以某种方式分成两半的算法。
  • 顺便说一句,所有答案似乎都忽略了linked_list.remove_node(max_value),我假设它的运行时间为N?这不会使函数 O(N^3) 吗?
  • @xingZì:这是一个加法步骤,而不是乘法步骤。它与查找步骤具有相同的行为((n + 1) / 2 每一步的平均工作量),因此合并它仅意味着工作量是n * ((n + 1) / 2 + (n + 1) / 2);将两个(n + 1) / 2s 结合起来,就可以简化为n * (n + 1)。对于 big-O,+ 1 被忽略,所以它仍然是 O(n²)。如果find_max 函数返回最大节点,则代码会更快(因此可以使用O(1) 工作将其删除,而不是在O(n) 处搜索),但大O 是相同的;该算法可能需要两倍的时间,但它会以相同的方式扩展。
【解决方案2】:

它是n + n-1 + n-2 + ... + 1,它是算术序列,所以它是n(n+1)/2。所以在大 O 表示法中,它是 O(n^2)

【讨论】:

    【解决方案3】:

    别忘了,O-notation 处理最坏情况的复杂性,并描述了整个函数。就 O 表示法而言,以下两个函数的复杂度相同:

    64x^2 + 128x + 256           --> O(n^2)
    x^2 - 2x + 1                 --> O(n^2)
    

    在您的情况下(以及您的算法所谓的选择排序,选择列表中的最佳元素并将其放入新列表中;其他O(n^2) 排序包括插入排序 和 冒泡排序),您有以下复杂性:

    0th iteration: n
    1st iteration: n-1
    2nd iteration: n-2
    ...
    nth iteration: 1
    

    所以整个复杂度将是

    n + (n-1) + (n-2) + ... + 1  =  n(n+1)/2  =  1/2n^2 + 1/2n
    

    它仍然是 O(n^2),尽管它会处于该类的低端。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-11
      • 2023-03-23
      • 1970-01-01
      相关资源
      最近更新 更多