【问题标题】:Why is bubble sort time complexity referred to as n squared? [duplicate]为什么冒泡排序的时间复杂度称为 n 平方? [复制]
【发布时间】:2017-10-13 10:45:24
【问题描述】:

还有其他关于冒泡排序时间复杂度的问题,但这个问题不同。每个人都说冒泡排序最坏的情况是 O(n^2)。在列表的 i 次迭代后的冒泡排序中,列表的最后 i 个元素是有序的,不需要再次触摸或比较。如果您一次又一次地不必要地遍历最终元素,时间复杂度只会是 O(n^2)。

鉴于冒泡排序的一个主要特征是(输入大小减去迭代)之后的元素永远不需要再次比较,因为它在正确的位置,为什么说冒泡排序的时间复杂度是对我来说,我不认为是冒泡排序?即使在维基百科中,它也说时间复杂度是 O(n^2),然后只在文章的中途提到它可以“优化”到仅花费大约 50% 的时间,而不是不必要地比较最后 i 个元素。

我被提醒了这一点,因为我正在创建一个循环来检查世界上所有对象的碰撞,并且模式是我检查过的:

for (int i = 0; i < numberofobjects - 1; i++)
{
   {
      for (int iplusone = i + 1; iplusone < numberofobjects; iplusone++)
        // check collision between i and iplusone
   }
}

对于 400 个对象,O(n^2) 的时间复杂度为 400 * 400 = 160,000。然而,它只进行了 79,800 次比较,大约 50%,这正是维基百科所说的。这让我想起了冒泡排序,所以当我检查时,我很惊讶地看到每个人都说它是 O(n^2)。

这是否意味着每当有人提到冒泡排序时,他们指的是在已经排序的最终元素上不必要地重复的版本?此外,当比较不同的算法时,冒泡排序总是表现更差,但作者指的是明显糟糕的 n^2 版本吗?

【问题讨论】:

  • Gauss sez: Sum(i = 1, n){i} = (n^2+n)/2 最高项是n^2
  • 所有冒泡排序变体都是 O(n^2)。这只是意味着比较的数量随着 n^2 的增长而增长,具有一定的比例和恒定的偏移量。因此,如果您对 100 个元素进行排序,您将执行大约 10,000 次比较。它可能是一半,也可能是两倍,但它仍然以二次方的形式增长。
  • @Tom Karzes 我明白了,所以它实际上并没有说明特定实例的任何内容,只是它如何增长?这似乎没那么有用。此外,当您说您将执行大约 10,000 次比较时,如果您使用我正在考虑的冒泡排序,则不是这样。
  • 一半或两倍都没有关系,它仍然会增长为 n^2。如果将输入大小加倍,则运行时间将增加 4 倍。如果将输入大小增加 10 倍,则运行时间将增加 100 倍。 O(n^2)、O(0.5*n^2)、O(2*n^2)都是一样的,大家都用O(n^2)来表示。这是您想要的度量,因为它可以让您快速估计在可接受的时间内您可以处理多大的数据集。
  • 不是常数因子无所谓,只是在极限情况下被增长相形见绌。最简单的排序算法是 O(n^2)。最快的排序算法是 O(nlog(n))。现在假设你的慢速算法经过高度优化,只需要 0.5*n^2,而你的快速算法优化很差,需要 2*nlog(n)。现在看看 n 为 1000 时的复杂度:慢速算法需要 0.5*1000*1000 = 500,000,而快速算法需要 2*1000*10 = 20,000,所以它快了 25 倍(我在这里保守地使用 log2) .并且随着 n 的增长,该比率不断增长。

标签: c time-complexity big-o bubble-sort


【解决方案1】:

对于 400 个对象,O(n^2) 的时间复杂度为 400 * 400 = 160,000。然而它只进行了 79,800 次比较,大约 50%

是的,你对 79,800 次比较是正确的,但你没有很好地理解大 O 表示法。

首先,如果您仔细查看冒泡排序算法,您会注意到确切的步骤比较是:

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

这意味着在 n=400 时,您得到正好 400*399/2=79,800 次比较

虽然大 O 表示法告诉您总步数是:n(n-1)/2 = n^2/2 - n/2,而在大 O 表示法中,我们忽略低阶项和常数,我们只保留 n^2,所以它是 O(n^2)

您需要在这里了解的是,大 O 表示法不会告诉您确切的步骤,它只会告诉您一个上限,例如复杂度函数的高阶,这是针对 n 上的大值。它只是声明 "for big n the complexity-order of growth is c*n^2" - 它描述了当参数趋于特定值或无穷大时函数的限制行为。

【讨论】:

  • 因此,当有人比较算法并说冒泡排序很糟糕,因为它是 O(n^2)这是否意味着它实际上比很多人说的比其他人要好?
  • 不,冒泡排序算法是ONE,它是你提到的那个。为了比较算法,你不能计算exact comparisons,因为这可能很困难,我们只想知道大输入的渐近复杂度,所以在这种情况下大 O 很有用。 O(nlogn) 算法(合并排序)比 O(n^2)(渐近)好得多,因此是更好的算法。这仅适用于(我们关心的)渐近行为,例如对于大 N(N 是输入)...
  • 只是为了更好地理解它,想象一下 N = 10 ^ 20。一个 O(n^2) 算法大约执行 10^40 步,我们不在乎它是否执行 10^40/2 (或任何常数除法)仍然比执行大约 20*10^20 步的 O(nlogn) 算法太多而且最差,对于大 n 存在巨大差异。
  • 谢谢。我同意你的看法。但是如果不考虑常量,我认为常量可能会产生巨大的差异,例如,如果常量是 O(n^2 / 50),而 Big O 仍然认为只有 n^2,那就是巨大的差异,甚至可能比 O(n log n) 的情况更快,具体取决于常数。
  • 可能这些是使用 Big O 的一些缺点,当然,恰好 n^2 步的算法在运行时间上比 n^2/50 差。但是大 O 强调的是,对于大 n 并没有太大的区别,因为只有高阶才重要。为了更好地理解它,大 O 告诉您 只有渐近 行为,例如对于非常大的 n - 当 n= 10^20 或 10^100 时,它真的有区别 n^2 或 n^2/50 吗?什么都没有!
猜你喜欢
  • 2013-01-28
  • 2012-09-12
  • 1970-01-01
  • 2015-05-17
  • 1970-01-01
  • 2015-09-12
  • 1970-01-01
  • 2020-12-14
  • 2015-06-15
相关资源
最近更新 更多