一、原理
1、从待排序区间中选择一个值作为基准值。(通常选择最左侧元素或者最右侧元素)。
2、遍历整个待排序的区间,把比基准值小的元素放在基准值左侧,比基准值大的元素放在右侧。最后整个区间就会划分为三个部分:小于基准值的元素、基准值、大于基准值的元素。
3、再针对左侧整理好的区间和右侧整理好的区间继续进行下一步的操作,重复以上过程即可。
(肯定看了这个文字的解释还是一脸懵,那就用一个例子来看一下整个的排序过程)
二、图解:
需要排序的区间:{6,1,2,7,9,3,4,5,10,8}
基准值:右侧元素-8
蓝色箭头:从左往右,找比基准值大的数字
绿色箭头:从右往左,找比基准值小的数字
第一回合:
先从左往右,找比基准值大的数字:
再从右往左,找比基准值小的数字:
交换两个数字:
再向右找比基准值大的数字:
这时,我们就会发现,两个箭头重合了,此时交换重合位置的数字和基准值。
这个时候我们就会发现,基准值8左侧的元素都比8大,右侧的都小。这样就达到了我们的目的。但是此时排序还没有结束。
我们将8左侧的元素分成一个区间{6,1,2,7,5,3,4},右侧的元素分为另一个区间{8,9}。分别将这两个区间又按照上面的方法进行排序。
第二回合:
2.1:划分{6,1,2,7,5,3,4},此时基准值我设为4
先从左向后找比基准值大的数字,在从右向左找比基准值小的数字,最后交换位置。
再继续找,这个时候两个箭头在7的位置相遇了。
交换相遇位置的元素和基准值:
这个时候又会分出两个区间{3,1,2} 和 {5,6,7},再继续进行划分。(这里我就不具体的排序了)
2.2划分{8,9},基准值为9
先从左向右找比基准值大的数字,在从右向左找比基准值小的数字。
交换重合位置元素和基准值:
这个区间就排列有序了。
此时第二回合完了之后我们的这一组数字就变成了:
一直按照这样的方法把{3,1,2}和{5,6,7}进行排序之后进行合并,就会得到一组有序的数字。
这里需要注意的是:如果取最左侧为基准值,就必须先从右向左找,再从左向右找。如果取最右侧为基准值,就必须先从左向后找,再从右向左找。
三、递归实现快速排序:
public static void quickSort(int[] array) {
quickSortHelper(array,0,array.length-1);//辅助方法
}
private static void quickSortHelper(int[] array, int left, int right) {
if(left >= right) {
//说明这个区间中有0个或者1个元素
return;
}
int index = partition(array,left,right);//重合位置的下标
quickSortHelper(array,left,index - 1);//递归实现左区间
quickSortHelper(array,index + 1,right);//递归实现右区间
}
private static int partition(int[] array, int left, int right) {
int i = left;
int j = right;
int base = array[j];
while (i < j){
//循环从左向后找到比基准值大的元素
while (i < j && array[i] <= base) {
i++;
}
//代码走到这里,i有可能和j重合,也有可能是找到了比基准值大的元素
//下面,循环从由向左找比基准值小的元素
while (i < j && array[j] >= base) {
j--;
}
//交换i位置的元素和j位置的元素
swap(array,i,j);
}
//代码跳出循环之后,说明i和j重合了,就需要交换重合位置的元素和基准值。
swap(array,i,right);
return i;
}
private static void swap(int[] array, int i, int j) {
int tmp = array[j];
array[j] = array[i];
array[i] = tmp;
}
四、非递归实现快速排序
需要借助栈来模拟递归的一个过程。
public static void quickSortByLoop(int[] array) {
Stack<Integer> stack = new Stack<>();
stack.push(array.length - 1);
stack.push(0);
while (!stack.isEmpty()) {
int left = stack.pop();
int right = stack.pop();
if(left >= right) {
continue;
}
int index = partition(array,left,right);
stack.push(right);
stack.push(index + 1);
stack.push(index-1);
stack.push(left);
}
}