所以,最近,出于好奇,我买了CLRS的“算法导论”一书。当我开始阅读本书时,我注意到本书中的一些非常典型的算法以非常不同的方式实现。
给定CLRS的快速排序的实现与流行的Hoare快速排序算法有很大不同。
所以提出我的问题......
void insertion_sort_by_robertsedgewick(int a[],int n)
{
for(int i=0;i<n;i++)
{
for(int j=i;j>0;j--)
{
if(a[j]<a[j-1])
{
swap(a[j],a[j-1]);
}
}
}
}
是Robert Sedgewick在他的Coursera课程中使用的代码。
相比之下,CLRS中给出的插入排序实现是,
void insertion_sort_CLRS(int a[] , int n)
{
int key,j;
for(int i=1; i<n; i++)
{
key = a[i];
j = i - 1;
while(j>=0 && a[j]>key)
{
a[j+1] = a[j];
j--;
}
a[j+1] = key;
}
}
这有点奇怪的是运行时间。 当我运行两个不同的实现时,这是我的结果:
数组中的元素数量:10,000
Robert Sedgewick的实施时间:0.235926s
CLRS实施的时间:0.078608s
有人可以向我解释这些结果吗? 算法几乎相同。只有实施是不同的。如何在实施方面稍有不同会导致运行时间的巨大差异?
答案 0 :(得分:3)
您展示的Robert Sedgewick代码主要用于说明,而非性能。
在使用相同代码的 Algorithms 一书中引用自己:
通过缩短内部循环以将较大的条目移动到正确的位置而不是进行完全交换(因此,大大加快插入排序速度并不困难 将数组访问次数减少一半)。我们将这项改进留给练习
与他在Coursera课程中的快速排序代码类似,请参阅QuickSort Dijkstra 3-Way Partitioning: why the extra swapping?。
答案 1 :(得分:2)
我看到的CLRS实现的轻微效率是它不会立即交换元素,而只是向上复制元素并等待直到获得密钥的位置。然后将密钥复制到正确的位置。
如果在任何迭代中,则数组为:
1 2 3 6 7 8 5
^
并且指针位于5,然后在第一个版本中,步骤将是:
1 2 3 6 7 5 8
1 2 3 6 5 7 8
1 2 3 5 6 7 8
而在下一个版本中,步骤将是:
1 2 3 6 7 8 8
1 2 3 6 7 7 8
1 2 3 6 6 7 8
1 2 3 5 6 7 8