实现原理:
1、找出中值项M
2、将数据通过中值项分为 D1(所有小于等于M的数据) D2(所有大于M的数据)
3、在D1 D2中递归执行1/2/3
PS:中值项的选取,如果直接选取最中间的数据,在某些时候会导致快速排序的性能下降到O(N^2),
所以为了容错,选取数据的第一个,最后一个,中间的数据,对三个进行排序,再进行上诉的 1 2 3(1的规则在此说明)
快速排序和归并排序的区别:
1、归并需要额外的内存空间开销,是快速的两倍
2、快速排序是先利用枢纽对数组进行分组(基于大于和小于枢纽的上下两个数组),再递归
3、归并排序先递归,再进行排序
分治法理解: 快速是先治后分 ,归并是先分后治
归并排序请看 https://blog.youkuaiyun.com/fighterGuy/article/details/82179004
/**
* 快速排序 效率: 3千万: 1898 30万: 28
* 大O O(N*logN) 最差可能达到 O(N^2)
* @author ThinkPad
*
*/
public class FastSort {
private long[] longArr;
private int nElme;
public FastSort(int size) {
longArr = new long[size];
nElme = 0;
}
public void insert(long value) {
longArr[nElme++] = value;
}
public void display() {
for (int i = 0; i < nElme; i++) {
System.out.print(longArr[i] + " ");
}
System.out.println(" ");
}
public void quickSort() {
recQuickSort(0, nElme - 1);
}
public void recQuickSort(int left, int right) {
int size = right - left + 1;
// 快速排序对小于4个的数据不支持,所以需要用其他算法排序或者直接写代码进行三个数值交换
// 经试验得知 9的时候,用插入排序效果较好,故采用
// 也可以先采用快速排序,不处理少于4个的情况,排序后使用插入排序,插入排序对有序数组有很高的效率
//if (right - left <= 0) {
// 此处采用的是不对少于10个进行处理,先完成快速排序再插入排序,用目前的程序有问题,partitionIt方法中--会出错
// return;
//}
if (size < 10) {
insertSort(left, right);
} else {
// 找出三值中数项
long pivot = medianOfThree(left, right);
// 中数项作为将数组进行大小区分的枢纽传入,返回值为枢纽真实位置(后续不参与排序)
int position = partitionIt(left, right, pivot);
recQuickSort(left, position - 1);
recQuickSort(position + 1, right);
}
}
public int partitionIt(int left, int right, long pivot) {
// 最左侧的值是求三值中数项的最小值,没有和枢纽比较的必要,所以是 ++leftPart
int leftPart = left;
// 最右侧的值是求三值中数项的最大值,且将枢纽放到了 right - 1(表示数组倒数第二个值)的位置上,所以rightPart = right - 1
// 并且 比较的时候使用--rightPart(表示倒数第三个值)
int rightPart = right - 1;
while (true) {
while (longArr[++leftPart] < pivot)
;
while (longArr[--rightPart] > pivot)
;
if (leftPart >= rightPart) {
break;
} else {
swap(leftPart, rightPart);
}
}
// 此处需要将获取三值中数项时把中数放入right - 1的值放回leftPart的位置上,因为那个位置是其真实的位置
swap(leftPart, right - 1);
return leftPart;
}
//三值中数项,避免出现最差的O(N^2)的出现,从最右边找枢纽,可能会出现数据的数据都需要移动的情况,这是最差的
public long medianOfThree(int left, int right) {
int mid = (left + right) / 2;
if (longArr[left] > longArr[right]) {
swap(left, right);
}
if (longArr[left] > longArr[mid]) {
swap(left, mid);
}
if (longArr[mid] > longArr[right]) {
swap(right, mid);
}
// 将mid的中值项放在right - 1位置上,在排序的时候不需要对中值项进行对比,当排序完成之后将mid放回就可以
swap(mid, right - 1);
return longArr[right - 1];
}
private void swap(int left, int right) {
long temp = longArr[left];
longArr[left] = longArr[right];
longArr[right] = temp;
}
// 从left开始 left + 1和left开始比较, 一直到right 和right - 1进行比较
public void insertSort(int left, int right) {
int j;
for (int i = left + 1; i <= right; i++) {
long temp = longArr[i];
j = i;
while (j > left && longArr[j - 1] >= temp) {
longArr[j] = longArr[j - 1];
--j;
}
longArr[j] = temp;
}
}
}