堆CPU时间

时间:2015-02-16 15:49:04

标签: c++ heapsort

我已经在c ++中实现了Heapsort,它确实对数组进行了排序,但却给了我比预期更高的CPU时间。它应该花费nlog(n)触发器,它应该比至少像bubblesort和insertionsort更快地排序。

相反,它给予我比bubbleort和插入排序更高的CPU时间。例如,对于随机数组的int(大小为100000),我有以下cpu时间(以纳秒为单位):

  • BubbleSort:1.0957e + 11
  • InsertionSort:4.46416e + 10
  • MergeSort:7.2381e + 08
  • HeapSort:2.04685e + 11

这是代码本身:

   #include <iostream>
    #include <assert.h>
    #include <fstream>
    #include <vector>
    #include <random>
    #include <chrono>
    using namespace std;

    typedef vector<int> intv;
    typedef vector<float> flov;
    typedef vector<double> douv;


        void max_heapify(intv& , int);
        void build_max_heap(intv& v);

        double hesorti(intv& v)
        {
            auto t0 =chrono::high_resolution_clock::now();
            build_max_heap(v);
            int x = 0;
            int i = v.size() - 1;
            while( i > x)
            {
                swap(v[i],v[x]);
                ++x;
                --i;
            }
            auto t1 = chrono::high_resolution_clock::now();
            double T = chrono::duration_cast<chrono::nanoseconds>(t1-t0).count();
            return T;
        }
        void max_heapify(intv& v, int i)
        {
            int left = i + 1, right = i + 2;
            int largest;
            if( left <= v.size() && v[left] > v[i])
            {
                largest = left;
            }

            else
            {
                largest = i;
            }

            if( right <= v.size() && v[right] > v[largest])
            {
                largest = right;
            }

            if( largest != i)
            {
                swap(v[i], v[largest]);
                max_heapify(v,largest);
            }



        }

        void build_max_heap(intv& v)
        {
            for( int i = v.size() - 2; i >= 0; --i)
            {
                max_heapify(v, i);
            }

        }

1 个答案:

答案 0 :(得分:1)

堆排序的实现肯定存在问题。

查看hesorti,您可以看到它在调用build_max_heap后只是反转向量的元素。所以build_max_heap不仅仅是在制作堆,它实际上是对整个数组进行反向排序。

max_heapify已经出现问题:在堆的标准数组布局中,数组索引 i 的节点的子节点不是 i + 1 i + 2 ,但 2i + 1 2i + 2 。它是从build_max_heap向后从数组后面调用的。这是做什么的?

第一次调用时,在最后两个元素上(当 i = n-2 时),它只是确保较大的元素在较小的元素之前。在那之后调用它会发生什么?

让我们做一些数学归纳。假设,对于所有 j&gt; i ,在数字 v [j + 1] j 调用max_heapify之后>通过 v [n-1] 已经按降序排列,结果是数字 v [j] v [n-1] < / em>按降序排序。 (当 i = n-2 时,我们已经看到这是真的。)

如果 v [i] 大于或等于 v [i + 1] (因此 v [i + 2] 为好吧),不会发生掉期,当max_heapify返回时,我们知道 i n-1 的值是降序排列的。在另一种情况下会发生什么?

此处,largest设置为 i + 1 ,根据我们的假设, v [i + 1] 大于或等于 v [i + 2] (实际上所有 v [k] k> i + 1 )已经,所以针对&#的测试39;右&#39; index( i + 2 )永远不会成功。 v [i] v [i + 1] 交换,使 v [i] 成为 v中最大的数字[i] 通过 v [n-1] ,然后在从 i + 1 到结尾的元素上调用max_heapify。通过我们的归纳假设,这将按降序对这些元素进行排序,因此我们知道现在从 v [i] v [n-1] 的所有元素都是按降序排列。

通过归纳的力量,我们已经证明build_max_heap将对元素进行反向排序。它的作用方式是依次渗透元素,从后面开始,在它后面的反向排序元素中正确位置。

这看起来很熟悉吗?它是一种插入排序!除了反向排序外,所以当调用hesorti时,交换顺序会按顺序排列。

插入排序还具有 O(n ^ 2)平均行为,这就是为什么您获得与冒泡排序类似的数字的原因。由于插入步骤的复杂实现,它几乎肯定会变慢。

TL; DR:你的堆排序并不快,因为它实际上不是堆排序,它是一个向后插入排序,然后是就地排序逆转。