【问题标题】:Why bubble sort is faster than quick sort为什么冒泡排序比快速排序快
【发布时间】:2018-03-28 22:04:36
【问题描述】:

我尝试使用两种排序算法对列表进行排序:冒泡算法和快速算法。
为此,我分别使用 algorithms 模块和 bubble_sortquick_sort 。据我所知,第一个算法的复杂度是n^2,第二个是n*log(n)。但是我从这段代码中得到了意想不到的输出:

from algorithms.sorting import bubble_sort, quick_sort
import time

my_list = [1, 12, 33, 14, 52, 16, 71, 18, 94]
start1 = time.time()
for i in range(1000000):
    bubble_sort.sort(my_list)

end1 = time.time()
start2 = time.time()
for i in range(1000000):
    quick_sort.sort(my_list)

end2 = time.time()

print('Bubble sort:', end1 - start1)
print('Quick sort:',end2 - start2)

输出:

>>> Bubble sort: 7.04760217666626
>>> Quick sort: 8.181402921676636

为什么在这种情况下冒泡排序比快速排序快?

【问题讨论】:

  • 您的测试数据太小,n^2 没有意义
  • 并从尚未排序的列表开始。
  • 因为列表已经排序。根据选择枢轴元素的方式,快速排序在这种情况下可能会表现不佳。
  • 另外,您的数据已经排序。我不知道algorithms 模块(而且你没有说它来自哪里),但它看起来足够聪明,可以在内部循环没有执行任何交换时终止。所以在这种情况下,它对列表进行了一次传递,即 O(n)。

标签: python algorithm python-3.x


【解决方案1】:

算法的时间复杂度对运行时间提供任何保证;相反,它为该算法的渐近行为提供了一个估计。在您的情况下,n = 9 非常小,因此算法中隐藏常量的影响将变得比时间复杂度本身的差异更重要。

尝试重新运行您的程序,但这次使用更大的值 n(例如 n=10000)。要测试这两种算法的一般行为,请确保您的输入列表是随机排序的。您还可以尝试使用边缘情况列表(即已经排序)来观察快速排序的最差情况和冒泡排序的最佳情况。

【讨论】:

  • 我用 100 000 个元素运行 BubbleSort,在相同条件下它比 java.utils.Array.sort 快几倍。虽然这不是最重要的一个原因,但我从 GeeksForGeeks 页面上复制了关于冒泡排序的内容(如果你去那里看看第二个代码 sn-p 与优化版本)。我对它们每个进行了 100 次排序并计算了它们的平均值,每个排序都有一个随机生成的整数数组。我知道 java.utils.Array.sort 不是快速排序。所以我采用了我的 QuickSort 实现(最后作为枢轴,糟糕)。它给出了与 java.utils.Array.sort 相同的结果。
  • @user11655900 快速排序的最坏情况运行时间为 O(n^2),这取决于数据集和枢轴选择。您可能希望通过代码进行调试,以了解您的算法性能不佳的原因。
【解决方案2】:

快速排序的最坏情况运行时间是O(n^2)。最坏的情况取决于枢轴选择策略,通常它发生在已经排序的数组(您的数组是)。

此外,对于小型数据集,冒泡排序或其他简单排序算法通常比更复杂的算法运行得更快。原因是,对于每次迭代,简单算法的计算量都比复杂算法少。

例如,假设冒泡排序每次迭代采用3ms,而快速排序采用20ms。所以对于带有10 项的数组。

在这种情况下,冒泡排序采用10*10*3 = 300ms

快速排序采用10*log2(10)*20 = 664ms。 (考虑平均情况)

所以冒泡排序在这里更快。但随着我们采用更大的数据集,由于运行时复杂度较低,快速排序变得越来越高效。

【讨论】:

    【解决方案3】:

    那么这里最坏的运行时间是什么?

    快速排序:n^2 和 冒泡排序:n^2

    请记住,最坏的情况并不总是能很好地反映现实世界的表现。在一般情况下,

    快速排序:nlog(n)

    冒泡排序:n^2

    因此基于此,快速排序比冒泡排序更快。

    但是,快速排序处理退化的情况很差。当列表已经几乎排序时,快速排序将继续递归。冒泡排序将在完成后立即停止,从而在这种情况下使冒泡排序更快。

    【讨论】:

      【解决方案4】:

      首先,尝试对更大的数组进行排序,以便二次复杂度优先于对数复杂度。
      注意:关于对数复杂度,请注意 log(n)quicksort 而言,不是 log10,是log2 -> O(n) 应该记为n * lg(n)

      其次,没有理由对已排序的数组进行排序...试试这个:

      import numpy as np
      arr = np.linspace(-1e3, 1e3, 1e5)
      np.random.shuffle(arr)  # Shuffling array preserving the content
      

      如果您的算法不接受 numpy 数组,请将其转换为列表:
      arr_l = list(arr)

      【讨论】:

        【解决方案5】:

        对于所有 n >= 1,在数学上 n^2 大于 nlog(n)。

        因此对于 n = 9(来自示例),冒泡排序{O(n^2)} 应该比快速排序{O(nlog n)} 慢。

        但实际的复杂度是:

        Big-O 冒泡排序:n(n-1) 等价于 O(n^2)

        Big-O 快速排序:O(n(log n))

        但由于n=9非常小,n^2和n是可比的,假设n^2-n等于n就错了

        至于证明:

        n=9 的 n^2-n 是 7.2

        n(log n) 对于 n=9 是 8.5 这与问题中提到的相同。

        【讨论】:

        • n^2-n for n=9 是 72,而不是 7.2
        猜你喜欢
        • 2017-03-18
        • 2011-11-30
        • 2019-02-26
        • 2017-01-30
        • 2021-11-24
        • 2022-01-15
        • 1970-01-01
        • 1970-01-01
        • 2012-08-26
        相关资源
        最近更新 更多