基本思想
通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部
分记录继续进行排序,以达到整个序列有序的目的。
核心函数分区
public static int partition(int[] a, int low, int high) {
//用子表的第一个记录作为中枢值
int pivotKey = a[low];
while(low < high) {
while(low < high && a[high] >= pivotKey) {
high--;
}
//将比中枢值小的放到低端
swap(a, low, high);
while(low < high && a[low] <= pivotKey) {
low++;
}
//将比中枢值大的放到高端
swap(a, low, high);
}
return low;
}
//排序算法中用的比较频繁
public static void swap(int[] test,int i,int j) {
int temp = test[i];
test[i] = test[j];
test[j] = temp;
}
分析
分区函数要做的,就是先选取子表当中的关键字,比如第一个关键字,然后想尽办法将它放到一个位置,使得他左边的值都比它小,右边的值都比它大。
举例:int [] test = {50,10,90,30,70,40,80,60,20};
1. 程序开始执行,此时Iow = 0 ,high = test .length -1 = 9 ,我们将测试[0] 赋值给枢轴变量pivotkey
2.进入while循环.test [8] = 20 < pivotkey = 50,不执行高 - 语句,然后执行swap(a,low,high),将比中枢值小的放到低端。
至于内层为什么用而而不用,如果?
举个例子:int [] test = {50,10,90,30,70,40,80,60,65};此时测试[8]> pivotkey,执行高 - ,然后进行交换,将测试[ 7]与test [0]交换了,但是测试[7]> pivotkey,此时不应该进行交换的,如果使用while的话,直到比pivotkey 小时才进行交换。但使用if排序不会出错,后面代码会再交换回来,因为执行了一些不必要的操作,所以性能上会慢一点。建议使用while
3.low = 2 high = 8 test[low]=90> pivotkey=50 交换test[2]与test[8]
4.high = 5 low=2 test[high]=40< pivotkey=50 交换test[5]与test[2]
5.low = 4 high = 5 test[low]=70> pivotkey=50 交换test[4]与test[5]
6.low=high=4;退出循环,此时枢轴左边的值都比50小,右边都比50大
快速排序代码
public static void quickSort(int[] a, int low, int high) {
//中枢值
int pivot = 0;
if (low < high) {
pivot = partition(a,low,high);
quickSort(a, low, pivot - 1);
quickSort(a, pivot + 1, high);
}
}
快速排序优化
1.优化选取枢轴
如果给定数组第一个元素并不是中间数,比如{9,1,5,8,3,7,4,6,2},我们选取9作为枢轴,经过一轮分区()函数后
所以对于枢轴的选取将会很大程度的影响性能。这里提出了“ 三数取中 ”的方法。
//计算数组中间元素的下标
int mid = low + (high - low) / 2;
//交换左端右端数据,保证左端较小
if(a[low] > a[high]) {
swap(a, low, high);
}
//交换中间右端数据,保证中间较小
if(a[mid] > a[high]) {
swap(a, high, mid);
}
//交换中间左端数据,保证左端较小
if(a[mid] > a[low]) {
swap(a, low, mid);
}
//此时a[low]已经为整个序列左中右三个关键字的中间值
//用子表的第一个记录作为中枢值
int pivotKey = a[low];
2.优化不必要的交换
while(low < high) {
while(low < high && a[high] >= pivotKey) {
high--;
}
//将比中枢值小的放到低端
//swap(a, low, high);
a[low] = a[high];
while(low < high && a[low] <= pivotKey) {
low++;
}
//将比中枢值大的放到高端
a[high] = a[low];
//swap(a, low, high);
}
a[low] = pivotKey;
return low;
还有一些优化的操作我这里就不一一赘述了,大家有兴趣可以去看相关书籍