【发布时间】:2017-11-13 04:24:48
【问题描述】:
在我的堆和未排序列表中插入 100000000 个元素后,似乎堆插入实际上更快(12 秒对 20 秒)。为什么是这样?我相信堆插入是O(logn),而未排序的列表插入是O(1)。我还注意到我的堆插入实现实际上并没有随着输入的数量而扩展。这也让我感到困惑。
这是我运行的代码:
int main ()
{
clock_t unsortedStart;
clock_t heapStart;
double unsortedDuration;
double heapDuration;
int num_pushes = 100000000;
int interval = 10000;
ofstream unsorted ("unsorted.txt");
ofstream heap ("heap.txt");
UnsortedPQ<int> unsortedPQ;
HeapPQ<int> heapPQ;
unsortedStart = clock();
for (int i = 0; i < num_pushes; ++i)
{
if (i % interval == 0) {
unsortedDuration = ( clock() - unsortedStart ) / (double) CLOCKS_PER_SEC;
unsorted << unsortedDuration << " " << i << endl;
}
unsortedPQ.insertItem(rand() % 100);
}
heapStart = clock();
for (int i = 0; i < num_pushes; ++i)
{
if (i % interval == 0) {
heapDuration = ( clock() - heapStart ) / (double) CLOCKS_PER_SEC;
heap << heapDuration << " " << i << endl;
}
heapPQ.insertItem(rand() % 100);
}
return 0;
}
这是插入的堆实现(使用std::vector):
template <class T>
void HeapPQ<T>::insertItem(T data) {
//insert into back of heap (std::vector)
dataArray.push_back(data);
int i = dataArray.size() - 1;
//sifts the inserted element up
while (i != 0 && dataArray[(i - 1) / 2] > dataArray[i]) {
swap(dataArray[i], dataArray[(i - 1) / 2]);
i = (i - 1) / 2;
}
}
这是插入的未排序列表实现(使用std::list):
//pushes element to the back of a std::list
template <class T>
void UnsortedPQ<T>::insertItem(T data) { dataList.push_back(data); }
【问题讨论】:
-
向量使用一个连续的内存块。现代硬件非常非常擅长访问和扫描连续的 RAM 块。
-
您是否在可以并行化/具有多个内核的东西上运行它?如果是这种情况,那么操作系统级别可能会通过将所有内容视为连续的内存块来优化它。
-
@OmegaNalphA 是的,我的机器有多个内核。但无论如何,随着元素数量的增加,堆插入应该花费更长的时间,但这似乎不会发生。
-
永远不要低估如果条件不利,在 O(1) 中执行单次迭代需要多长时间。
-
区别可能在于分配的数量:
std::list可能在每个push_back上进行分配std::vector仅使用对数数量的分配(或者可能是单个一,正确初始化时)。还要避免昂贵的计时操作:不要在每次1000插入时写入文件,而是将原始计时存储在预先分配的数组中,并在运行后处理该数组 - 同时预热缓存!要明白我的意思:尝试颠倒unordered和heap的顺序,你可能会得到不同的结果。
标签: c++ list data-structures heap