记录一路快速排序、二路快速排序、三路快速排序的区别和改进
基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,比另一部分的关键字大,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
一路快速排序步骤
1、从数列中挑出一个元素,设为V
2、重新排序数列,所有元素比V值小的摆放在V前面,所有元素比V值大的摆在V的后面(相同的数到右边),在这个分区退出之后,V就处于数列的中间位置。
3、递归把小于V的子数列和大于V的子数列排序。
缺点:是遇到大量相同元素会大大浪费时间复杂度,不符合期望
代码实现
public class QuickSort01 extends Sort{
public QuickSort01(int[] arr) {
super(arr);
}
@Override
public void sort() {
quickSort(0,arr.length - 1);
}
private void quickSort(int L, int R) {
if (L >= R) {
return;
}
//先对数组划分 并返回划分后的中点
int p = partition(L ,R);
quickSort(L, p - 1);//划分完的再排一遍
quickSort(p + 1, R);
}
private int partition(int L, int R) {
//优化一下 随机让后面的数字和第一个数字换一下
//随机一个角标尽量避免极端情况
//L = 5 R = 10 [0,5] + 5 = [5,10]
swap(L, (int) (Math.random() * (R - L + 1) + L));
int v = arr[L];//让首位在递归中继续当中值
//arr[l+1 ~ j] < v < arr[j+1 ~ i)
int j = L;
for (int i = L + 1; i <= R; i++) {
if (arr[i] < v) {
swap(j + 1, i);
j++;
}
}
swap(L, j);//换位
return j;
}
}
二路快速排序
步骤
1、从数列中挑出一个元素,设为V
2、重新排序数列,左右两路各有一个游标,当左路游标i大于当前V,则由后遍历右路游标j,遇到比V小的就与当前左路游标i交换,这样反复直到两游标相遇。(代码操作中左i走到不小于V的停下,右j不大于V的停下,然后交换两个值再重复)
3、递归重复把小于V的子数列和大于V的子数列排序。
最终目的是将相等元素大致均分到两边,来减少后续递归的次数避免极端情况。
代码实现
//双路快速排序
public class QuickSort02 extends Sort {//实现抽象类
public QuickSort02(int[] arr) {//引用父类构造副本
super(arr);
}
@Override
public void sort() {
quickSort(0, arr.length - 1);
}
private void quickSort(int L, int R) {
if (L >= R) {//判断
return;
}
//对数组进行划分 并返回划分后的中点
int p = partition(L, R);
quickSort(L, p - 1);
quickSort(p + 1, R);
}
private int partition(int L, int R) {
//优化一下 随机让后面的数字和第一个数字换一下
//尽量避免极端情况(升序情况)
swap(L, (int) (Math.random() * (R - L + 1) + L));
int v = arr[L];
int i = L + 1;
int j = R;
while (true) {
while (i <= R && arr[i] < v) {//判断i的角标不越界,走到一个不小于V的停
i++;
}
while (j >= L + 1 && arr[j] > v) {//走到一个不大于V的停
j--;
}
if (i > j) {//判断不越界
break;
}
swap(i, j);
i++;
j--;
}
swap(L, j);//把V换到中间
return j;
}
}
三路快速排序
跟前两路的最大区别就是单独开辟一个中间区来存放相同的元素,再从两头遍历交换。
就像是对左边区与中间区做一路快排,将左边区合并中间区一起与右边区做二路快排。
代码如下
//三路快速排序
public class QuickSort03 extends Sort {
public QuickSort03(int[] arr) {
super(arr);
}
@Override
public void sort() {
quickSort(0, arr.length - 1);
}
private void quickSort(int L, int R) {
if (L >= R) {
return;
}//随机一下元素
swap(L, (int) (Math.random() * (R - L + 1) + L));
int v = arr[L];
int lt = L;
int gt = R + 1;
int i = L + 1;
while (i < gt) {
if (arr[i] < v) {//左边扩
swap(i, lt + 1);
lt++;
i++;
} else if (arr[i] > v) {//右边扩
swap(i,gt - 1);
gt--;
} else {//中间区
i++;
}
}
//划分区
swap(L,lt);
quickSort(L,lt - 1);
quickSort(gt, R);
}
}