【问题标题】:Why is my heapsort faster than Javas and C++s sort functions?为什么我的堆排序比 Java 和 C++ 的排序函数快?
【发布时间】:2013-11-14 22:27:04
【问题描述】:

我最近学会了如何使用堆和堆排序的美妙之处。我决定将 heapsort 与 C++ 中的 std::sort 和 Java 中的 Arrays.sort() 进行比较。我对一个整数数组进行了排序,每个整数在

我在 Java 中将 100,000,000 个整数生成到一个数组中,然后运行 ​​Arrays.sort(),然后生成新的随机序列并运行我的 heapSort()。这是我的 Java 程序的输出:

Arrays.sort time: 10.923 seconds.

Heap sort time: 1.402 seconds.

所以堆排序快了大约 8 倍。

然后我在 C++ 中运行了类似的代码,这次使用 std::vector 作为我的容器(因为 std::sort 需要两个迭代器)。

C++ 结果:

Heapsort: 3.213

std::sort: 37.264

所以在我的程序中,std::sort 大约慢了 12 倍。

在 Java 中,我使用 System.currentTimeMilis() 测量时间,而在 C++ 中,我使用来自 .

的 clock()

这是在 Windows 7、四核 Intel i5 2500k、超频至 4.8GHz 上测试的。 C++ 是使用-Wall -pedantic 标志编译的。

谁能告诉我这是怎么回事?堆排序真的那么快吗?还是我在代码中犯了错误?我不想用大量代码淹没这篇文章,所以我会在文章末尾链接它。

顺便说一句:是的,我知道 Arrays.sort() 是稳定的,而 heapsort 不是。 Java 没有不稳定的排序(至少,我还没有找到)。这就是我在 C++ 中使用 std::sort 的原因,看看它是否与稳定性有关。

源代码,C++ 和 Java:https://gist.github.com/anonymous/7475399

【问题讨论】:

  • 这是一个错误吗? int tmp = heap[0]; heap[i] = heap[0]; heap[i] = tmp;
  • IIRC Java Arrays.sort() 已超载。对于内置类型的数组,允许实现使用非稳定排序,但对于Object 类型的数组,它必须是稳定的。因此,如果实现选择使用稳定的排序算法,即使是内置类型,也不能怪你将它与堆排序进行比较。
  • “为什么我比已经部署和审查了数百万次的标准库代码更令人惊叹” => 仔细检查程序的正确性...
  • “我在 Java 中将 100,000,000 个整数生成到一个数组中,然后运行 ​​Arrays.sort(),然后生成新的随机序列并运行我的 heapSort()”。为什么不生成一个序列,复制它,使用每种算法对一个序列进行排序,然后比较结果呢?这将使您很好地了解您的代码是否正确。
  • 在验证代码是否实际计算正确结果之前(即验证它是否是您要进行基准测试的代码),您应该(几乎)永远不要对代码进行基准测试。鉴于到目前为止的 cmets 和答案,您显然跳过了这一步。

标签: java c++ sorting


【解决方案1】:

你的 Java 代码在我看来有问题

int tmp = heap[0];
heap[i] = heap[0];
heap[i] = tmp;

这不是交换两个元素的代码。

这对执行时间有影响吗?我对堆排序的了解不够好,无法确定。

【讨论】:

  • 它使 heapify 成为空操作。没有进行排序。
【解决方案2】:

您的 Java(正如 john 指出的)和 C++ 代码中的项目都没有正确交换:

void heapSort(vector<int> & heap, int length)
{
    int heapsize = length;
    buildHeap(heap, heapsize);
    for(int i = heapsize-1; i >= 1; i--)
    {
        int tmp = heap[0];
        heap[i] = heap[0];
        heap[i] = tmp; // overwrote the item you just tried to swap!
        heapsize--;
        heapify(heap, 0, heapsize);
    }
}

简而言之,您的代码“更高效”,因为它根本不进行任何排序。

【讨论】:

    【解决方案3】:

    您的 C++ 代码中还有一个问题与您生成随机分布的方式有关:

    int randomval()
    {
      double d;
      int result;
      d = rand() / RAND_MAX;
      result = (int) (d * N);
      return result;
    }
    

    d 始终是0,因为您执行int 除法,然后隐式将其转换为double。简而言之,您的 randomval 函数根本没有给您任何随机值。

    当您使用自己的堆排序对其进行排序时,始终会执行相同的代码路径。在您的情况下,heapify 可能永远不会执行这部分代码:

    if (largest != i)
    {
        int tmp = heap[i];
        heap[i] = heap[largest];
        heap[largest] = tmp;
    
        heapify(heap, largest, heapsize);
    }
    

    这就是为什么你的实现看起来更快。

    使用实际分布修复随机测试数据我认为您会发现您的实现速度较慢:

    #include <random>
    // snip...
    int main()
    {
      int length = 10000000;
      std::vector<int> vint1;
    
      std::default_random_engine gen;
      std::uniform_int_distribution<int> randomval(1, N);
      for (int i = 0; i < length; i++)
      {
            vint1.push_back(randomval(gen));
      }
      std::vector<int> vint2 = vint1; /* so we're sorting same testdata for both */
      // ...
    

    再次运行基准测试显示:

    g++ -std=c++0x -Wall -pedantic -O2 heapsorttest.cpp -o heapsorttest.exe
    heapsorttest.exe
    
    Heapsort: 5.822s
    true
    
    std::sort: 0.936s
    true
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-11
      • 1970-01-01
      • 2021-06-19
      • 1970-01-01
      • 2015-06-25
      • 2011-11-30
      • 2018-03-28
      相关资源
      最近更新 更多