思路:
1.分治思想:先划分成两个问题,然后对两个子问题递归排序,最后再合并。
2.核心算法:快排的核心在于划分问题(找到分界点)。
代码:
//快速排序
public static void quickSort(int[] arr, int left, int right) {
if(left < right) {
//此处用单指针扫描来划分(可以替换划分方法)
int fenjiedian = singleScan_partition(arr,left,right);//从分界点开始分成两段子问题
quickSort(arr,left,fenjiedian-1);//递归解决子问题1
quickSort(arr,fenjiedian+1,right);//递归解决子问题2
}
}
快排的三种划分方法:
1.单指针扫描划分:
思路:p1作为扫描指针,找到比pivot大的元素则停下与p2元素交换,p2后移。
代码:
//单指针扫描
public static int singleScan_partition(int[] arr, int left, int right) {
//确定参考值
int pivot = arr[left];
//建立p1指针
int p1 = left+1;
//建立p2指针
int p2 = right;
while(p1 <= p2) {
//p1指的元素小则前移,否则就与p2交换,p2后移
if(arr[p1] <= pivot){
p1++;
} else {
Util.swap(arr,p1,p2);
p2--;
}
}//当p1指针和p2指针交叉的时候退出循环
//画草图举例分析可以知道最终p2所在位置就是两个子问题的分界点
Util.swap(arr,p2,left);
return p2;
}
2.双指针扫描划分:
思路:p1找到比pivot大的元素停下,p2找到比pivot小的元素停下,然后交换p1,p2元素
代码:
//双指针扫描
public static int doubleScan_partition2(int[] arr, int left, int right) {
//指定参考值
int pivot = arr[left];
//创建p1指针
int p1 = left+1;
//创建p2指针
int p2 = right;
//p1与p2交叉时退出循环
while (p1 <= p2) {
//注意:!!!!!!!!条件要并上 p1 <= p2
while(p1 <= p2 && arr[p1] <= pivot) p1++;
while(p1 <= p2 && arr[p2] > pivot) p2--;
if(p1 <= p2) Util.swap(arr,p1,p2);
}
//p2所在下标即为分界点
Util.swap(arr,p2,left);
return p2;
}
3.三指扫描划分
思路:p1指针遇到大于pivot的元素停下,p2遇到小于pivot元素停下,此时交换p1,p2,p1遇到等于pivot的元素则equal跑过来,p1继续前移,遇到小于pivot的数则与equal交换。
代码:
//三指针扫描(待定复盘)
public static int threeScan_partition(int[] arr, int left, int right) {
int pivot = arr[left];
int p1 = left+1;
int equal = p1;
int p2 = right;
while(p1 <= p2) {
//遇到大的元素和等于的元素p1都可能停下
while(p1 <= p2 && arr[p1] < pivot) p1++;
//遇到小的元素p2停下
while(p1 <= p2 && arr[p2] >= pivot) p2--;
//遇到相等的元素,equal移动到p1位置,p1前移
while(p1 <= p2 && arr[p1] == pivot) {
equal = p1;
p1++;
}
//如果p1因为遇到比equal更小的元素而停下
if(p1 <= p2 && arr[p1] < arr[equal]) Util.swap(arr,p1,equal);
//否则p1和p2同时停下
else if(p1 <= p2) {
Util.swap(arr,p1,p2);
}
}//循环结束后,p1与p2交叉
Util.swap(arr,left,p2);
return p2;
}
收获:
1.快排和核心算法在于分区,在同一个数组上通过指针位移比较,进行元素的交换。
2.与归并排序不同的是,归并排序重在合并,其中要建立辅助空间拷贝原数组,再进行指针位移比较,然后把元素覆盖到原数组的位置。
3.复盘的时候一边写注释梳理思路一边写代码。