快速排序的改进
Posted
技术标签:
【中文标题】快速排序的改进【英文标题】:Improvement of quick sort 【发布时间】:2015-03-19 08:07:55 【问题描述】:快速排序算法在有很多副本时表现不佳。(我的意思是我们有重复数据)。如何改进这个问题。
int partition (int low,int high)
int j=low,i=low+1;
int PivotItem=arr[low];
for(int i=0,j=0;i<n;i++)
if(arr[i]==PivotItem)
subarray[j]=arr[i];
for(i=low+1;i<=high;i++)
if(arr[i]<PivotItem)
j++;
swap(arr[i],arr[j]);
swap(arr[low],arr[j]);
int PivotPoint=j;
return PivotPoint;
void quick_sort(int low,int high)
if(low==high)
return ;
int PivotPoint=partition(low,high);
quick_sort(low,PivotPoint-1);
quick_sort(PivotPoint+1,high);
【问题讨论】:
您的目标是特定的语言平台吗?在 Java 中,Collections.sort()
实际上会进行合并排序,尤其是为了避免不必要的数据复制。在 C++ 中,您有单独的 sort
(合并)和 qsort
(快速排序)。另外,您所说的“项目副本”是什么意思?如果您有涉及重复的数字列表,则不能说它们是副本。他们只是复制部分数据。
你的意思是很多重复的项目还是重复很多次的项目?
@YvesDaoust:例如,我们有 111133333332222999999999000000031115553333。
尝试每层缩进 4 个空格。
可以选择压缩数据:将序列转换为(value, repeat count)
表示,对其进行快速排序并恢复为原始表示。
【参考方案1】:
QuickSort 有一个特殊的修改,称为dutch flag sort algorithm。它对小于、等于和大于枢轴项值的项使用三向分区。
【讨论】:
在此之上,可以使用双支点实现三向分区。 @greybeard 你的意思是iaroslavski.narod.ru/quicksort/DualPivotQuicksort.pdf 吗?当然,该算法对于许多重复项的情况都有好处(但似乎并不能完全解决问题) 这将是引用次数最多的论文的最值得注意的 URL。这是对具有统一访问时间的通用排序的公平尝试。 几个不重复的键似乎比许多键重复更容易。【参考方案2】:我假设您的意思是快速排序基于<=
(或<
,然后结果与下一个解释对称)比较器比较元素,如果我们看一下所有元素都是与枢轴x
相同,您将获得快速排序的最坏情况复杂性,因为您将数组分成两个非常不均匀的部分,一个大小为n-1
,另一个为空。
解决此问题的快速解决方法是仅对 <
和 >
使用快速排序 - 将数据拆分为两个子数组,而不是单个枢轴,保存一个数组保存所有等于pivot的元素,然后对严格大于pivot的元素和严格小于pivot的元素进行递归,合并三个数组。
插图:
legend: X=pivot, S = smaller than pivot, L = larger than pivot
array = |SLLLSLXLSLXSSLLXLLLSSXSSLLLSSXSSLLLXSSL|
Choose pivot - X
Create L array of only strictly smaller elements: |SSSSSSSSSSSSSSS|
Create R array of only strictly larger elements: |LLLLLLLLLLLLLLLLLL|
Create "pivot array" |XXXXXX|
Now, recurse on L, recurse on R, and combine:
|SSSSSSSSSSSSSSS XXXXXX LLLLLLLLLLLLLLLLLL|
【讨论】:
我把我的代码放在我的问题中。如何在我的代码中实现你的解决方案? @sarina 你需要让partition
持有一个所有元素的子数组等于主元(或元素范围),当你完成后,递归从l
开始这个子数组的末尾,从这个子数组的末尾到r
。具体有什么不明白的请追问,我会尽量详细说明。
我在分区函数中创建了子数组。你是认真的吗?之后我做什么?以上是关于快速排序的改进的主要内容,如果未能解决你的问题,请参考以下文章