端循环;
b.从左端开始,如果有比枢轴记录大的数,此时左端循环终止,同样不采取交换low和high位置的值,而是直接将low位置的值赋给high位置,这时high位置的值是交大的记录,而此刻的low位置的值没有变;
c.一轮左右循环完毕,此时low位置的值是之前那个交大的值,它被赋给high处,这里就需要加一个小步骤,将之前存起来的枢轴记录赋给low位置,然后进入下一轮循环;
优化代码:
[java]
int pivotKey = array[low]; // 将三取一后的中间值作为枢轴记录
while (low < high) {
while (low < high && array[high] >= pivotKey) {
high--;
}
array[low] = array[high]; // 把比枢轴记录小的值赋给low下标的记录
while (low < high && array[low] <= pivotKey) {
low++;
}
array[high] = array[low]; // 把比枢轴记录大的值赋给high下标的记录
array[low] = pivotKey; // 然后将枢轴记录赋给low
}
@关键处之一:array[low] = array[high]; // 把比枢轴记录小的值赋给low下标的记录;
@关键处之二:array[high] = array[low]; // 把比枢轴记录大的值赋给high下标的记录;
@关键处之三:array[low] = pivotKey; // 然后将枢轴记录赋给low;
整合两种优化:
[java]
/**
* 优化后快速排序的核心程序,枢轴记录用了三取一,去前中后三个数中间那个
*
* @param low
* @param high
* @param array
* @return 返回枢轴记录
*/
private int partition(int low, int high, int... array) {
int mid = (low + high) / 2;
//枢轴记录三取一,优化的代码,用于待排序数组元素不是很大的时候
{
if (array[low] > array[high]) {
swap(low, high, array);
}
if (array[mid] > array[high]) {
swap(mid, high, array);
}
if (array[mid] > array[low]) {
swap(mid, low, array);
}
}
int pivotKey = array[low]; // 将三取一后的中间值作为枢轴记录
while (low < high) {
while (low < high && array[high] >= pivotKey) {
high--;
}
array[low] = array[high]; // 把比枢轴记录小的值赋给low下标的记录
while (low < high && array[low] <= pivotKey) {
low++;
}
array[high] = array[low]; // 把比枢轴记录大的值赋给high下标的记录
array[low] = pivotKey; // 然后将枢轴记录赋给low
}
return low; // 返回枢轴记录的下标
}
@上面采取三数取中和省略不必要的交换两种优化;
3.递归操作的优化:
在数据结构中,有一种结构是栈,函数的递归调用实则是将每一次调用压到栈中,然后按后进先出的原则执行函数中的代码,所以递归对性能有一定的影响,在快速排序中,用到了两次递归,加入待排序的序列是及不平衡的,递归深度趋近于n,与平衡时的log2n的慢得多,另一个栈的大小也是有限的,每一次递归调用都会耗费一定的栈空间,函数的参数也会是空间耗费加大,所以这里可以减少递归的调用,能提高性能:
双递归调用代码:
[java]
/**
* 快速排序的递归调用
* @param low
* @param high
* @param array
*/
private void quickSort(int low, int high, int... array) {
if (low < high) {
int pivot = partition(low, high, array); // 找到枢轴记录的下标
quickSort(low, pivot - 1, array); // 对低子表进行递归排序
quickSort(pivot + 1, high, array); // 对高子表进行递归排序
}
}
@判断条件是if(low < high) 然后,获取枢轴记录,分别对两端进行递归调用,这里可以优化:
尾递归:
[java]
/**
* 快速排序的尾递归调用
*
* @param low
* @param high
* @param array
*/
private void quickSort(int low, int high, int... array) {
while (low < high) {
int pivot = partition(low, high, array); // 找到枢轴记录的下标
quickSort(low, pivot - 1, array); // 对低子表进行递归排序
low = pivot + 1; // 尾递归
}
}
@这一这里相当于方法quickSor在执行一次时,用了while(low < high)这个循环条件,这里就是关键所在
a.第一次进入循环:这个循环执行了一次递归后,然后执行low = pivot + 1;
b.再次进入循环:执行int pivot = partition(low, high, array);,对右端进行递归,因为(low = povit + 1) > (high = povit -1 ),所以后面的quickSort(low, pivot - 1, array);将会终止,然后重复执行a,b;
4.小数组的优化:
当数组较小时,用快速排序似乎有点牛刀杀鸡的感觉,所以灵活运用之前学过的排序算法,引入直接插入排序吧,那么,什么是较小的数组,没有一个统一的标准,我们可以认为给定一个标准,比如50被认为为小数组(也有7的),那么当数组长度小于50时,调用直接插入排序,其余调用快速排序,这个很好理解的,只需加一个判断条件就可以了:
代码实现:
[java]
/**
* 快速