在CLRS第2章中,有一个练习,询问是否将插入排序的最坏情况运行时间改进为O(n lg n)
。我看到this question并发现它无法完成。
最坏情况下的复杂性无法改善,但与单独移动数组元素相比,使用memmove
实际运行时间会更好吗?
单独移动元素的代码
void insertion_sort(int arr[], int length)
{
/*
Sorts into increasing order
For decreasing order change the comparison in for-loop
*/
for (int j = 1; j < length; j++)
{
int temp = arr[j];
int k;
for (k = j - 1; k >= 0 && arr[k] > temp; k--){
arr[k + 1] = arr[k];
}
arr[k + 1] = temp;
}
}
使用 memmove
void insertion_sort(int arr[], int length)
{
for (int j = 1; j < length; j++)
{
int temp = arr[j];
int k;
for (k = j - 1; k >= 0 && arr[k] > temp; k--){
;
}
if (k != j - 1){
memmove(&arr[k + 2], &arr[k + 1], sizeof(int) *(j - k - 2));
}
arr[k + 1] = temp;
}
}
我无法让第二个完美地运行,但这是我想要做的一个例子。
使用memmove
?
答案 0 :(得分:6)
{C}后面的实现可能会在您的C库中进行更优化。一些架构具有非常有效地一次移动整个存储器块的指令。理论运行时间复杂度不会得到改善,但它在现实生活中可能仍会运行得更快。
答案 1 :(得分:3)
memmove
将完美地调整以最大限度地利用可用的系统资源(当然,每个实现都是唯一的)。
以下是来自专家C编程 - 深度C秘密的一个引用,介绍了使用循环和使用memcpy
之间的区别(前面是两个代码片段,一个将源复制到一个目的地使用for
循环和另一个memcpy
):
在这种特殊情况下,源和目标都使用相同的 缓存行,导致每个内存引用错过缓存和 在处理器等待常规内存传送时停止处理器。 库
memcpy()
例程特别针对高性能进行了调整。 它将循环展开以读取一个高速缓存行然后写入 避免这个问题。使用智能副本,我们得到了巨大的成功 性能改进。这也显示了绘画的愚蠢 来自简单的基准程序的结论。
这可以追溯到1994年,但它仍然说明了标准库函数与您自己推出的任何内容相比有多优化。循环案例运行大约需要7秒,而memcpy
运行大约需要1秒。
虽然memmove
只会略微慢于memcpy
,但由于需要对源和目标做出假设(memcpy
中它们不能重叠),它仍应远远优于#include <string.h>
#define DUMBCOPY for (i = 0; i < 65536; i++) destination[i] = source[i]
#define SMARTCOPY memcpy(destination, source, 65536)
int main()
{
char source[65536], destination[65536];
int i, j;
for (j = 0; j < 100; j++)
DUMBCOPY; /* or put SMARTCOPY here instead */
return 0;
}
到任何标准循环。
请注意,这不会影响复杂性(正如另一张海报所指出的那样)。复杂性不依赖于更大的缓存或展开的循环:)
这里要求的是代码片段(略有变化):
$ time ./a.out
real 0m0.002s
user 0m0.000s
sys 0m0.000s
在我的机器上(32位,Linux Mint,GCC 4.6.3)我得到以下时间:
使用SMARTCOPY:
$ time ./a.out
real 0m0.050s
user 0m0.036s
sys 0m0.000s
使用DUMBCOPY:
{{1}}
答案 2 :(得分:2)
这完全取决于您的编译器和其他实现细节。确实memmove
可以用一些棘手的超优化方式实现。但与此同时,智能编译器可能能够找出每个元素复制代码正在做什么,并以相同(或非常类似)的方式对其进行优化。试一试,亲眼看看。
答案 3 :(得分:0)
你不能用C实现击败memcpy。因为它是用asm编写的,并且具有良好的算法。
如果你为特定的cpu编写asm代码,并开发一个考虑缓存的好算法,你可能有机会。
标准库函数经过优化,使用它们总是更好。