堆排序CPU时间
Heapsort CPU time
我在c++中实现了Heapsort,它确实对数组进行了排序,但给了我比预期更高的CPU时间。它应该花费nlog(n)个flops,并且它应该至少比bubblesort和insertitionsort更快地对其进行排序。
相反,它给了我比bubblesort和insertion-sort更高的cpu时间。例如,对于int的随机数组(大小100000),我有以下cpu时间(以纳秒为单位):
- 气泡排序:1.0957e+11
- 插入排序:4.46416e+10
- 合并排序:7.2381e+08
- 堆排序: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);
}
}
堆排序的实现肯定有问题。
查看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>i,在一个数组上调用索引为j的max_heapify
之后,其中数字v[j+1]到v[n-1]已经按降序排列,结果是数字v[j][n-1][em>按降序排列。(我们已经看到,当i=n-2时,这是真的。)
如果v[i]大于或等于v[i+1][因此,v[i+2]到n-1处的值按降序排列。在另一种情况下会发生什么?
这里, 通过归纳的力量,我们证明了 这看起来熟悉吗?这是插入排序!除了它是反向排序之外,所以当调用 插入排序也有O(n^2)的平均行为,这就是为什么你会得到与冒泡排序相似的数字。由于插入步骤的复杂实现,它几乎肯定会更慢。 TL;DR:你的堆排序并不快,因为它实际上不是一个堆排序,它是一个向后插入排序,然后是一个原位排序反转。largest
被设置为i+1,并且根据我们的假设,v[i+1]大于或等于v[i+2][事实上,对于k>i+1的所有v[k]+2)的测试永远不会成功v[i][em>与v[i+1][em>交换,使v[i][em>成为从v[i][im>到v[n-1][em>的最大数,然后对从i+1到末尾的元素调用max_heapify
。根据我们的归纳假设,这将按降序对这些元素进行排序,因此我们知道,现在从v[i]到v[n-1]build_max_heap
会对元素进行反向排序。它的方法是从后面依次过滤元素,使其在后面的反向排序元素中处于正确的位置hesorti
时,交换序列会将其按正确的顺序排列。
- 分别测量每个线程上花费的 CPU 时间(C++)
- 对于等待以 std::future wait() 返回的函数的 CPU 使用率或检查标志在循环中休眠一段时间哪个更好?
- 一段时间后 CPU 使用率高
- C/C++memcpu基准测试:测量CPU和墙时间
- 超过CPU时间限制:当MPI_Sent一个非常大的int*时
- 如何测量一组特定线程的 CPU 时间?
- OpenCV 3.4 C++ Cuda 加速比 CPU 花费更多时间
- 如何以C++而不是 CPU 时间测量挂钟时间
- 将返回 CPU 时间提升为 0
- C++中的双感叹号(!!)会花费更多的CPU时间吗
- 为什么内存访问时间远远超过CPU缓存大小时会增加
- 在我的CUDA运行时间计划中,CPU和GPU可以异步计算,但不能合作地计算
- 即使使用睡眠,线程也不会放弃CPU时间
- 以C++为单位测量程序的 CPU 时间和挂钟时间
- 在 Windows 上以C++计算 CPU 时间
- 一段时间后,C++应用程序占用100%的cpu周期
- 时间短函数与 CPU 时间使用 RTEMS 操作系统
- PDH 无法通过 PdhAddCounter() 访问总 CPU 时间
- 二叉搜索真的是在 0 时钟 CPU 时间内执行的吗?
- 我应该检查什么:cpu时间还是墙时间