大桌子的快速排序出奇地慢
Posted
技术标签:
【中文标题】大桌子的快速排序出奇地慢【英文标题】:strangely slow quicksort for large tables 【发布时间】:2014-12-30 15:07:09 【问题描述】:我一直在做作业,比较一堆排序算法,我遇到了一个奇怪的现象。事情正如预期的那样:插入排序赢得了诸如 20 个整数的表之类的东西,否则快速排序优于堆排序和归并排序。最多包含 500,000 个整数的表(存储在内存中)。对于 5,000,000 个整数(仍存储在内存中),快速排序突然变得比堆排序和归并排序更糟。数字始终是均匀分布的随机数,windows 虚拟内存关闭。有人知道这可能是什么原因吗?
void quicksortit(T *tab,int s)
if (s==0 || s==1) return;
T tmp;
if (s==2)
if (tab[0]>tab[1])
tmp=tab[0];
tab[0]=tab[1];
tab[1]=tmp;
return;
T pivot=tab[s-1];
T *f1,*f2;
f1=f2=tab;
for(int i=0;i<s;i++)
if (*f2>pivot)
f2++;
else
tmp=*f1;
*f1=*f2;
*f2=tmp;
f1++; f2++;
quicksortit(tab,(f1-1)-tab);
quicksortit(f1,f2-f1);
;
【问题讨论】:
我不知道您使用的是什么系统,但我的第一个猜测是由于数据集较大,您遇到了更多的处理器缓存未命中。 对于大型数组,选择一个好的枢轴值比简单地运行算法更重要。试试T pivot=tab[s/2];
看看有什么帮助
每次运行代码时都会更改种子值,还是始终使用相同的初始 500 万大小数组?
你说“突然更糟”,但你没有具体说明有多突然,以及有多糟。例如,它在 4999999 时是否更快,然后在 5000000 时更差?如果逐渐恶化,您能否描述或展示性能曲线的样子?
@jxd: 肯定是reseeded,2,000,000 qs 运行时间几乎是mergesort 的一半,3000,000 是一样的。
【参考方案1】:
可能是您的数组现在比 L3 缓存大。
快速排序分区操作将随机元素从数组的一端移动到另一端。典型的 Intel L3 缓存为 8MB。使用 5M 4 字节元素 - 您的数组为 20MB。你正在从它的一端写到另一端。
L3 之外的缓存未命中进入主内存,并且可能比更高级别的缓存未命中慢很多。
到目前为止,您的整个排序操作完全在 CPU 内部运行。
【讨论】:
谢谢,可能是这样。我将在可能具有不同 CPU 的不同机器上检查此代码。我的是 i7-2630QM(6MB 4 核共享 l3 缓存)。 仍然让我感到困惑的是为什么快速排序与合并排序有很大不同。很明显,堆排序在使用 L3 缓存约束时会做得很糟糕——元素几乎以随机方式读取和写入。然而,在快速排序和合并排序中,表都是在本地访问的。快速排序需要维护缓存中原始表的一部分,靠近移动指针f1
和靠近f2
。合并排序不仅需要在两个移动指针附近存储两个半数组,还需要至少存储它要合并到的表的一部分。【参考方案2】:
当数组中有许多重复项时,您的算法开始失败。您只在大值时注意到了这一点,因为您一直在为算法提供具有大跨度的随机值(我假设您使用 rand() 和:0 - RAND_MAX ),并且该问题仅出现在大数组中。
当您尝试对相同数字的数组进行排序时(尝试对 100000 个相同的数字进行排序,程序将崩溃),您将首先遍历整个数组,不必要地交换元素。然后你把数组一分为二,但是大数组只减了1:
v
quicksortit(tab,(f1-1)-tab);
因此,您的算法变为 O(n^2),并且您还消耗了大量的堆栈。在这种情况下,寻找更好的支点对您没有帮助,而是选择不存在此缺陷的 quicksort() 版本。
例如:
function quicksort(array)
if length(array) > 1
pivot := select middle, or a median of first, last and middle
left := first index of array
right := last index of array
while left <= right
while array[left] < pivot
left := left + 1
while array[right] > pivot
right := right - 1
if left <= right
swap array[left] with array[right]
left := left + 1
right := right - 1
quicksort(array from first index to right)
quicksort(array from left to last index)
修改版:http://rosettacode.org/wiki/Sorting_algorithms/Quicksort
【讨论】:
谢谢。这确实是部分原因。最初,数字的范围是 0-9999。对RAND_MAX
范围内的数字进行排序会使事情变得更好,即它提高了快速排序变坏的限制。以上是关于大桌子的快速排序出奇地慢的主要内容,如果未能解决你的问题,请参考以下文章
快速排序到底有多快?(含代码分析9大排序算法并行运行对比视频)