算法-快速排序(quick sort)
思路
1.先从数组里找出基准数。2.分治,将数组中比基准数小的放一边,比基准数大的放另外一边(这样的话就是以基准数为中心,将数组分成了两段了)。3.将分出的左右区间继续上面1,2的步骤,直到每个区间都有一个数字。
这里简单看看上面的思路就可以看得出,快排其实也是用了分治法的思维来排序,从而达到了O(nlogn)的时间复杂度。
接着我用图来一步一步解释一下快速排序的步骤
假设现在有一个待排序的数组
int[] arr = {7, 5, 6, 9, 3, 1, 4};
找基准数(这里假设我们把每次的最左边的数来作为基准数) 这里以7作为基准数,然后用双指针标记数组的左边和右边,依次往中间判断。
第一步是4比7小,将4赋值给左指针,紧接着往右移动被赋值好的指针。
第二步是5比7小,继续后移指针。
第三步是6比7小,继续后移指针。
第四步是9比7大,将9赋值给右指针,同时右指针向前移动。
第五步是1比7小,将1赋值给左指针,同时左指针向后移动。
第六步是3比7小,指针直接往后移动。
第七步发现指针重叠了(其实就是找到了基准数的位置了,把7放在重叠的位置)
这样第一轮的基准数就找到了,接下来只需要将数组按新的基准数分区,找到新的基准数,然后一直重复上面的步骤就可以完成快速排序了。
问题
快速排序的话如果一直按以最左边来作为基准数的话是有问题的,假如说数组本身就是倒序的
int[] arr = { 9, 8, 7, 6, 5, 4};
那么其实这么找的话,快速排序的时间复杂度就跟O(n2)没什么区别,所以这里的话是最好把每次选择的基准数作为随机数来选择。这里的话我简单就用了下中位数来作为基准数。
代码
public class QuickSort {
public static void main(String[] args) {
int[] arr = { 7, 5, 6, 9, 3, 1, 4 };
quickSort(arr, 0, arr.length - 1);
System.out.println("排序后:");
for (int i : arr) {
System.out.println(i);
}
}
private static void quickSort(int[] arr, int left, int right) {
// 在左右指针没有重合的时候继续分治的找
if(left < right) {
// 这里找到基准数
int index = getIndex(arr, left, right);
// 根据基准数继续分成左右两个区间找(分治法的思维)
quickSort(arr, left, index-1);
quickSort(arr, index+1, right);
}
}
private static int getIndex(int[] arr, int left, int right) {
swap(arr, left, left + (right-left)/2);
int temp = arr[left];
while (left<right) {
while(left<right && arr[right] >= temp) {
right--;
}
arr[left] = arr[right];
while (left < right && arr[left] <= temp) {
left++;
}
arr[right] = arr[left];
}
arr[left] = temp;
return left;
}
}
最后
其实还有别的基准数选择方式,这里需要大家去自行挖掘了!