解题思路:
快速排序的基本思想是:先对数组进行一次划分partition。划分的目的是在数组中选择一个数,作为支点pivot,数组中所有比pivot小的元素放置在数组的左边,数组中所有比pivot大的元素放置在数组的右边。这个分界索引是在索引的移动过程中所确定。具体来说,设置两个索引分别为start和end分别指向数组待排序范围的起始位置和结束位置,在支点的左边找到一个比支点元素大的,在支点的右边找到一个比支点元素小的,交换这两个元素,start右移,end左移,直到start和end错开后,所有start之前的元素都是比支点元素小的,所有start之后的元素(包括start)都是比支点大的元素,因此可以确定分界索引。一旦确定这个分界索引,接下来,递归地对数组的左边进行一次快速排序,对数组的右边进行一次快速排序。
public class Solution {
public int partition(int[] arr, int start, int end) {
if (arr == null || arr.length == 0
|| start < 0 || start >= arr.length
|| end < 0 || end >= arr.length ) {
return -1;
}
//保存数组的开始和结束索引,不能直接在start和end上进行操作,因为一旦改变,会影响后续的递归
int i = start;
int j = end;
//获取支点元素索引
int pivotIndex = (start + end) / 2;
//获取支点元素
int pivot = arr[pivotIndex];
//接下来将比支点元素小的元素全放在支点的左边,比支点元素大的元素放到支点的右边
while (i <= j) {
//在支点的左边找到一个比支点大的元素
while (arr[i] < pivot) {
//这个循环有一个隐含的信息,就是start最多只会和pivot的索引相等,不会到达支点的右边
//因为当arr[start] == pivot,循环就已经结束
i ++;
}
//在支点的右边找到一个比支点小的元素
while (arr[j] > pivot) {
//同理,包含隐含信息,end最多只会和pivot的索引相等,不会到达支点的左边
//因为当arr[end] == pivot,循环就结束了
j--;
}
if (i <= j) {
swap(arr, i, j);
i++;
j--;
}
}
//i左边的元素都是比支点元素小的,j右边的元素都是比支点大的
//让i作为分界线
return i;
}
public void quickSort(int[] arr, int start, int end) {
if (start == end) {
return;
}
int index = partition(arr, start, end);
if (start < index) {
//对左边进行一次快速排序
quickSort(arr, start, index - 1);
}
if (index < end) {
//对右边做一次快速排序
quickSort(arr, index, end);
}
}
//交换索引指向的元素
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}