- 1960年由查尔斯·安东尼·理查德·霍尔(Charles Antony Richard Hoare,缩写为C.A.R.H)
- 昵称为东尼·霍尔(Tony Hoare )
- 执行流程:
- 从序列中选择一个轴点元素(pivot)
假设每次选择0位置的元素为轴点元素 - 利用pivot将序列分割成2个子序列
将小于pivot的元素放在pivot前面(左侧)
将大于pivot的元素放在pivot后面(右侧)
等于pivot的元素放哪一边都可以 - 对于序列进行1.2操作
知道不能再分割(子序列中只剩下1个元素)
- 快速排序的本质:
- 逐渐将每一个元素都转成轴点元素
轴点构成
时间复杂度
- 在轴点左右元素数量比较均匀的情况下,同时也是最好的情况
T(n) = 2*T(n/2) + O(n) = O(nlogn) - 如果轴点左右元素数量极度不均匀,最坏情况
T(n) = T(n-1) + O(n) = O(n²) - 为了降低最坏情况的出现概率,一般采取的做法是
随机选取轴点元素 - 最好、平均时间复杂度:O(nlogn)
- 由于递归调用的缘故,空间复杂度:O(logn)
- 属于不稳定排序
与轴点相等的元素
- 如果序列中的所有元素都与轴点元素相等,利用目前的算法实现,轴点元素可以将序列分割成2个均匀的子序列
- 思考:cmp位置的判断分别改为<=、>=会起到什么效果?
while (begin < end) {
if (cmp(pivot, array[end]) <= 0) {
end--;
} else {
array[begin++] = array[end];
break;
}
}
while (begin < end) {
if (cmp(pivot, array[begin]) >= 0) {
begin++;
} else {
array[end--] = array[begin];
break;
}
}
- 轴点元素分割出来的子序列极度不均匀
- 导致出现最坏时间复杂度O(n²)
最终版本
public int[] sortArray(int[] nums) {
sort(nums, 0, nums.length);
return nums;
}
private void sort(int[] nums, int begin, int end) {
if (end - begin < 2) return;
int mid = pivotIndex(nums, begin, end);
sort(nums, begin, mid);
sort(nums, mid + 1, end);
}
private int pivotIndex(int[] nums, int begin, int end) {
int index = begin + (int)(Math.random() * (end - begin));
int tmp = nums[begin];
nums[begin] = nums[index];
nums[index] = tmp;
int pivot = nums[begin];
end--;
while (begin < end) {
while (begin < end) {
if (pivot < nums[end]) {
end--;
} else {
nums[begin++] = nums[end];
break;
}
}
while (begin < end) {
if (pivot > nums[begin]) {
begin++;
} else {
nums[end--] = nums[begin];
break;
}
}
}
nums[begin] = pivot;
return begin;
}