C++ 三路快排 模板
前言:今天被大作业的快速排序折磨的焦头烂额,原 C++
sort选手发现简洁的快排竟然如此难写(边界要注意的点好多 qwq)。
我原先的快排长这样:题解 P1177 【【模板】快速排序】 - 沧海之耀 的博客 - 洛谷博客 (luogu.com.cn)
三路快排:快速排序 - OI Wiki (oi-wiki.org)
先在 arr[l,r] 中随机一个 val
快排当前层的目标是将数值分为 < val | = val | > val 三类,也按这个顺序分开,然后分别递归 < val 和 > val 两类。
算法思路:
- 
在工作过程中,维护 arr[l,r]的这样一个性质。arr[l,j) < val | arr[j,i) = val | arr[i,k] 未分类 | arr(k,r] > val只要从左到右扫描 i,直至arr[i,k]为空即可。
- 
变量定义 - 
i: 要分类的对象 (从左到右扫描) ,[l,i)是已经分类好的< val | = val
- 
j:arr[l,j) < val, arr[j,i) = val,j表示 第一个 值为val的下标,若暂时没有=val的值,则j=i。
- 
k: 维护一个右侧> val的垃圾堆。(k,r]是> val的部分
 
- 
- 
工作流程: - 
从左到右扫描 
- 
arr[i] > val的放到右侧(与arr[k]交换),这里i不能右移,因为 换过来的arr[k]还要判断。
- 
arr[i] < val的与arr[j]交换,i右移,j右移,维护arr[l,j) < val, arr[j,i) = val。
- 
arr[i] = val,不动,i右移即可。
 
- 
- 
具体实现: 
// 三路快排 
void qsort(int arr[],int l,int r)
{
	if(l>=r) return;
	int i=l,j=l,k=r;
	int val=arr[l+rand()%(r-l+1)];
	while(i<=k) {
		if(arr[i]<val) 
			swap(arr[i++],arr[j++]); // 这里可,前面是安全的。 
		else if(val<arr[i]) 
			swap(arr[i],arr[k--]); // 这里 i 不能 ++, 还要判断一下后面扔过来的东西。 
		else i++;
	}
	
	qsort(arr,l,j-1); qsort(arr,k+1,r);
}
- 
时间复杂度分析: - 
每次循环 \(i\) 增加或 \(k\) 减少,于是每层 \(O(len)\) 
- 
总共 平均 \(O(n\log n)\) 
 
- 
这样实现三路快排, 比较好的解决了相同值多,或者选到最小或最大的 val 导致问题规模不缩小的问题。排序一次问题规模必缩小 。
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号