快排
- 基本思想:
- 分治法+递归。
- 快排主要分两个部分:
- partition:选一个pivot,将数组分成左右两个部分。
- 左边的数据都小于 pivot,右边的都大于 pivot。
- recursive:
- 快排pivot 的 左边部分 与 右边部分。
- partition:选一个pivot,将数组分成左右两个部分。
- 填坑法:
-
代码:
class Solution { public int[] sortArray(int[] nums) { quickSort(nums, 0, nums.length-1); return nums; } private void quickSort(int[] nums, int l, int r){ if(l>=r) return; int pos = partition(nums, l, r); quickSort(nums, l, pos-1); quickSort(nums, pos+1, r); } private int partition(int nums[], int l, int r){ int pivot = nums[l]; while(l<r){ while(r>l && nums[r]>=pivot) r--; nums[l] = nums[r]; // System.out.println(Arrays.toString(nums)+", l: "+l+", r: "+r); while(l<r && nums[l]<=pivot) l++; nums[r] = nums[l]; // System.out.println(Arrays.toString(nums)+", l: "+l+", r: "+r); } nums[l] = pivot; // System.out.println(Arrays.toString(nums)+", l: "+l+", r: "+r); return l; } }
-
优化pivot的选择:随机选择pivot,然后把pivot swap到 左边left的位置,其余都可以按照上面写。
class Solution { public int[] sortArray(int[] nums) { quickSort(nums, 0, nums.length-1); return nums; } private void quickSort(int[] nums, int l, int r){ if(l>=r) return; int pos = partition(nums, l, r); quickSort(nums, l, pos-1); quickSort(nums, pos+1, r); } private int partition(int[] nums, int l, int r){ int pivot = getPivot(nums, l, r); while(l<r){ while(r>l && nums[r]>=pivot) r--; nums[l] = nums[r]; while(l<r && nums[l]<=pivot) l++; nums[r] = nums[l]; } nums[l] = pivot; return l; } private int getPivot(int[] nums, int l, int r){ int i = new Random().nextInt(r-l+1)+l; swap(nums, l, i); return nums[l]; } private void swap(int[] nums, int a, int b){ int t = nums[a]; nums[a] = nums[b]; nums[b] = t; } }
快排的复杂度
- 空间复杂度:使用了递归,每次递归用常数级的空间,因此:
O(logn)
- 时间复杂度:
- 最好的情况:每次partition 后 pivot 都在中间,递归 O(logn) 次,每次 partition 需要 O(n),最好情况下的时间复杂度为
O(nlogn)
。 - 最差的情况:数组是已经是有序的,pivot partition后的位置总是在边上,T(n) = T(n-1) + T(0) + O(n),需要递归 O(n) 次,复杂度为
O(n^2)
。 - 平均情况:
O(nlogn)
- 最好的情况:每次partition 后 pivot 都在中间,递归 O(logn) 次,每次 partition 需要 O(n),最好情况下的时间复杂度为