【问题标题】:insertion sort vs bubble sort vs quicksort algorithm插入排序 vs 冒泡排序 vs 快速排序算法
【发布时间】:2012-10-06 11:20:16
【问题描述】:

我正在课堂上进行一项研究 我测试了冒泡排序和插入排序以及快速排序,我对随机数进行了测试。 结果表明,插入排序比冒泡排序快,而快速排序最慢。

所以我的时间排名如下

  1. 插入排序(最快)
  2. 冒泡排序(第二分)
  3. 快速排序(最慢)

考虑到插入和冒泡排序的复杂度为 O(n2) 而 快速排序 O(n log n) 和 O(n log n) 应该更快!!!

谁能跟我解释一下?

谢谢

(NSMutableArray *)quickSort:(NSMutableArray *)a
{
    // Log the contents of the incoming array
    NSLog(@"%@", a);

    // Create two temporary storage lists
    NSMutableArray *listOne = [[[NSMutableArray alloc]
    initWithCapacity:[a count]] autorelease];
    NSMutableArray *listTwo = [[[NSMutableArray alloc]
    initWithCapacity:[a count]] autorelease];
    int pivot = 4;

    // Divide the incoming array at the pivot
    for (int i = 0; i < [a count]; i++)
    {
        if ([[a objectAtIndex:i] intValue] < pivot)
        {
           [listOne addObject:[a objectAtIndex:i]];
        }
        else if ([[a objectAtIndex:i] intValue] > pivot)
        {
           [listTwo addObject:[a objectAtIndex:i]];
        }
    }

    // Sort each of the lesser and greater lists using a bubble sort
    listOne = [self bubbleSort:listOne];
    listTwo = [self bubbleSort:listTwo];

    // Merge pivot onto lesser list
    listOne addObject:[[NSNumber alloc] initWithInt:pivot]];

    // Merge greater list onto lesser list
    for (int i = 0; i < [listTwo count]; i++)
    {
        [listOne addObject:[listTwo objectAtIndex:i]];
    }

    // Log the contents of the outgoing array
    NSLog(@"%@", listOne);

    // Return array
    return listOne;
}

【问题讨论】:

  • 您正在测试的数据有多大,您是否对每个算法使用相同的未排序数据?
  • 你要么实现了快速排序错误,要么你做错了测试。发布您的实现和测试。
  • 对于少量元素,插入排序比快速排序更快,因为虽然 O(N^2) 它有一个非常小的常数因子。为了获得更好的结果,请尝试对包含大量元素(例如 1000、1000000、1000000000 个元素)的数组进行排序。我不知道对于小型数组,bubblesort 的表现如何,但我猜只有少数元素它可能会胜过快速排序。
  • 首先想到的问题是:您使用了多少数据?您是否打印了起始列表并看到这些数字实际上是随机的?您在快速排序中找到拆分值的算法是什么?
  • 你所谓的“快速排序”不是快速排序。它是一个分区,然后是两个冒泡排序加上一个合并。

标签: objective-c algorithm sorting quicksort bubble-sort


【解决方案1】:

好吧,快速排序很大程度上依赖于输入。在进行快速排序之前,您需要 SHUFFLE 输入。 如果您的输入已排序,则快速排序的复杂度可能为 O(n2)

对于小型数组,插入排序也可以更快

【讨论】:

  • 我测试了几批 5000 、 10000 、 15000 和 20000 相同的数组适用于所有三种算法是否足以使插入排序更快
  • 快速排序围绕一个元素进行分区。要获得 O(n log n),您需要确保该元素接近均值。一种方法是在快速排序之前随机输入。
  • 例如,如果您已对输入进行排序并围绕第一个元素进行分区,那么您将拥有 1/2 o(N2) 复杂度
  • 如果我将枢轴点硬编码为中间数字,可以吗?即 5000 可以将枢轴设为 2500 吗??
  • @OracleOracle 对于任何选择固定元素作为枢轴的策略,都有一些输入会导致快速排序 O(n²)。如果数组真的是随机的(或一个很好的近似值),那么这些情况就不太可能发生。如果您选择每个中位数的枢轴,则保证为 O(n*log n),但常数因子相对较大,平均而言,它会比更简单的枢轴选择策略慢。中值 3 使得 O(n²) 行为不太可能发生,因此这是一个很好的策略。选择数组的中间元素比第一个要好,但坏情况比中位数 3 多。
【解决方案2】:

O(nlogn)O(n^2)“更快”,但让我们回忆一下大 O 符号的含义。

这意味着如果算法 A 的复杂度为 O(nlogn),对于某些常量 N_1c1,对于每个 n&gt;N - 算法“更快”然后 c1*n*log(n)。如果算法 B 有O(n^2),则有一些常量N_2,c2 使得算法“更快”然后c2 * n^2 * log(n) 用于n &gt; N_2

但是 - 在此 N 之前会发生什么?这个常数C 是什么?我们不知道。 算法B 仍然可能比算法A 对于小输入“更快”,但对于大输入 - 实际上,A 会更快(渐近界更好)。

例如,假设算法AT_1(n) = 10* nlog(n) ops 中运行,而算法BT_2(n) = n^2 中运行。对于n=3 - 我们得到T_1(3) = 10*3*2 = 60(我们为log(n) 使用ceil)和T_2(3) = 9 - 因此算法B,尽管O(n^2)A 更快。

关于快速排序和插入排序:
快速排序通常非常快,并且在极少数情况下会衰减到二次时间(如果我们选择随机元素作为枢轴,这种情况发生的可能性很小)。

但是,快速排序中大 O 符号后面的常数大于插入排序。因此 - 一种可能的优化是:使用快速排序直到达到某个阈值(比如 30 个元素),然后使用插入排序而不是快速排序对这个子数组进行排序。 This post 讨论此优化。

冒泡排序(根据经验)对于随机数组很糟糕,但如果数组几乎已排序并且“不合适”的元素在其开头,则可能会很好。

【讨论】:

    【解决方案3】:

    这取决于数组大小。在小型数组上,简单的算法(例如插入排序)会做得很好,不需要更好的算法。

    但是,当 n 很大时(例如 n=10000000),快速排序通常比插入(或冒泡)排序要好得多。

    【讨论】:

    • 但我不明白为什么插入排序在小号中更好,你能解释一下吗?
    • @OracleOracle:这是O(n^2)for (int = 0; i &lt; n*n; ++i) printf("%d\n", i); 的示例。这是O(n log n):for (int i = 0; i &lt; n * log(n); ++i) { for (int j = 0; j &lt; 1000*1000; ++j) printf("%d\n", i); } 的示例。显然,对于小的n,第一个代码比第二个代码快。那么,对于小的n,为什么插入排序不应该比快速排序更快,因为它的复杂性更差呢?它实际上更快的原因是快速排序具有插入排序没有的特定开销(跟踪分区)。
    • 再次感谢,冒泡排序和插入排序呢
    • @OracleOracle:我认为插入排序比冒泡排序需要更少的比较,也可能需要更少的副本。当然,冒泡排序的最坏情况(最小元素从末尾开始)需要n*(n-1) 比较,而插入排序最多需要一半。对于随机数据,很可能有接近结尾的小元素。它们被称为“海龟”,它们严重伤害了简单的冒泡排序。
    猜你喜欢
    • 2013-06-20
    • 2011-11-30
    • 1970-01-01
    • 2018-03-28
    • 2012-05-12
    • 2015-04-25
    • 2016-11-01
    • 2017-03-18
    • 2016-03-19
    相关资源
    最近更新 更多