【问题标题】:Java - Why is my Bubble Sort faster than my Insertion Sort?Java - 为什么我的冒泡排序比我的插入排序快?
【发布时间】:2015-02-06 00:12:14
【问题描述】:

我正在测量排序完成排序所需的步骤数,无论出于何种原因,冒泡排序似乎总是比插入排序快一点,根据我的阅读,它应该是相反的。

不会发布我的完整代码,但我相信问题可能在于我的计数在哪里。

冒泡排序:

public void sort()
{
    for (out = nElems-1 ; out >= 1 ; out--)
    {
        count = count+1;
        for (in = 0 ; in < out ; in++)
        {
            if ((a.get(in)) > (a.get(in+1)))
            {
                swap (in, in+1);
                count = count+2;
            }
        }
    }
}

插入排序:

void sort()
{
    Integer temp[] = new Integer[1];
    for (out = 1 ; out < nElems ; out++)
    {
        count = count+1;
        temp[0] = a.get(out);
        in = out;
        while (in > 0 && a.get(in-1) >= temp[0])
        {
            a.set(in, a.get(in-1));
            --in;
            count = count+2;
        }
        a.set(in, temp[0]);
    }
}

举个例子,我对 3 个文本文件进行了排序,其中填充了 2000 个随机整数,值介于 1-2000 之间,插入排序的平均值为 2,007,677 步,冒泡排序的平均值为 2,005,719。

【问题讨论】:

  • 如何计算步数?您不应该计算进行比较的次数吗?或者可能是对数组的访问次数(读取或写入)?
  • 是的,您在冒泡排序中缺少比较(最里面的 if,内部循环继续条件)。这只是两件事,我什至没有看过插入排序。
  • 如果你有 count=count+2 用于交换,你不应该只用 count=count+1 进行单向转移吗?
  • @Thilo 抱歉,这就是我所说的步骤。对于 2000 个整数的文件,最好的情况是 2000,最坏的情况是 400 万(2000^2)。对于这两种类型。
  • 好的,这让我更加困惑。对不起,伙计们,我是这个东西的新手。所以当你们谈论比较时,你们是在谈论 compareTo 吗?

标签: java sorting


【解决方案1】:

因此,首先,您只是衡量任务,而不是整体绩效。其次,您的插入排序具有不交换以移动值的优化,那么为什么每次都将 2 添加到 count ?您的 while 循环应该只将 1 添加到 count,然后当您有 a.set(in,temp[0]) 时,您应该在 while 循环之外再次添加 1。 (旁注 - 为什么temp 是一个数组而不仅仅是一个整数?) 现在,如果您想衡量整体性能,您需要衡量比较和分配(最好在两个单独的变量中,因为某些设备/架构对于这些操作可能具有非常不同的性能)。

编辑:

为了澄清,比较是当您将数组中的两个项目的值与小于 () 之类的运算符进行比较时。赋值是指您更改数组中的值(在您的情况下,使用a.set())。

这里有一些代码修改(我将 count 拆分为两个变量,代表您要测量的实际事物,assignmentscomparisons):

冒泡排序:

public void sort()
{
    for (out = nElems-1 ; out >= 1 ; out--)
    {
        for (in = 0 ; in < out ; in++)
        {
            comparisons = comparisons+1;
            if ((a.get(in)) > (a.get(in+1)))
            {
                swap (in, in+1);
                assignments = assignments+2;
            }
        }
    }
}

插入排序:

void sort()
{
    int temp = 0;
    for (out = 1 ; out < nElems ; out++)
    {
        count = count+1;
        temp[0] = a.get(out);
        in = out;
        comparisons = comparisons + 1; //You're doing the comparison below at least once
        while (in > 0 && a.get(in-1) >= temp[0])
        {
            a.set(in, a.get(in-1));
            --in;
            assignments = assignments+1;
            comparisons = comparisons + 1; 
        }
        a.set(in, temp[0]);
        assignments = assignments+1;
    }
}

要考虑的另一件事 - 您在哪里初始化变量 count?我在您的代码中没有看到它,实际上可能是您正在使用来自不同范围的相同变量,并且由于您没有将其重置为 0,因此您第二次执行的任何排序都会添加到您的第一个号码。

【讨论】:

  • 每次都加 2,因为它适用于正确的最佳/最坏情况(相信我,我一开始就尝试了 +1)。最好的情况是 2000,最坏的情况是 2000^2。我已经将 +1 添加到了我的 while 循环之外。至于临时数组作为数组,是我教授选择的,所以我只是决定效仿。
  • 好吧,如果您不进行移位优化,然后在找到正确位置后插入值,则添加 2 是正确的 - 也许您的示例最佳/最坏情况意味着没有优化?
  • 而不是编辑,因为我看到你做了一些工作。我正在使用 bigO,所以我有点困惑我是否应该测量作业、比较或两者(我假设两者)。我知道,在我的情况下,如果我有一个包含 1-2000 的 2000 个整数的文件,排序和已经排序的文件在这两种情况下都会给我 2000 的结果,在最坏的情况下会得到 2000^2 的结果。你的修改似乎给了我一些奇怪的结果。
  • 顺便说一下,这些排序在它们自己的类中,每个排序在类的开头都有一个计数设置为 1,因此在每个排序完成后它会重置为 1。
  • 我建议与老师澄清你应该测量什么,因为这肯定会影响你的测量。至于 2000^2 的值,我不确定您要使用哪种算法,或者您要测量什么,但我会尽力而为:如果您的意思是插入排序,那么对于每个项目(其中从 i) 的当前索引开始,将其插入(执行 i 分配)到第一个位置。这意味着您有 1+2+3+...+1999 的总和。这是 n^2 的数量级(参见求和公式),但不完全等于 n^2。
猜你喜欢
  • 2011-11-30
  • 2018-03-28
  • 2014-12-04
  • 2017-03-18
  • 2014-12-11
  • 1970-01-01
  • 2012-05-12
  • 2019-02-26
  • 2022-01-15
相关资源
最近更新 更多