单路快速排序的时间复杂度为O(nlog2n),空间复杂度为O(n)
单路快速排序的核心思想:选取一个标定元素,将数组二分(一般为非等分),保证左侧部分比标定元素小,右侧部分比标定元素大,即将标定元素放到该元素在数组中应该在的位置,如下图所示:
排序的过程和示意图如下:
- 随机选择一个位置的元素与数组首元素交换位置,作为标定元素V,此操作可以有效避免快速排序在排序近乎有序的数组时,退化为时间复杂度为O(n^2)的算法
- 从第二个元素开始,找到第一个比标定元素V大的元素,位置记为j+1,即j是已排序数组中最后一个比V小的元素。此操作可以提高近乎有序数组快排的效率
- 此时开始递归排序,如果新加入的元素大于等于标定元素V,则直接加入排序数据,并且i++
- 如果新加入的元素比V小,则j++,并且交换swap(arr[j], arr[i]),然后i++
- 直到排序所有元素,然后交换wap(arr[j], arr[L]),至此完成排序
代码如下:
template<typename T>
void quickSort(T arr[], int n) {
srand(time(nullptr));
_quickSort(arr, 0, n - 1);
}// 对arr[rangeL,rangeR]部分进行快速排序
template<typename T>
void _quickSort(T arr[], int rangeL, int rangeR) {
if (rangeL >= rangeR) {
return;
}
if (rangeR - rangeL <= 16) {
insertionSort(arr, rangeL, rangeR);
return;
}int index = _quickPartition(arr, rangeL, rangeR);
_quickSort(arr, rangeL, index - 1);
_quickSort(arr, index + 1, rangeR);
}// 对arr[rangeL,rangeR]部分进行_quickPartition操作
// 返回index, 使得arr[rangeL, index - 1] < arr[index] ; arr[index + 1, rangeR] > arr[index]
template<typename T>
int _quickPartition(T arr[], int rangeL, int rangeR) {
// 优化点:随机在arr[rangeR, rangeL]的范围中, 选择一个数值作为标定点pivot
swap(arr[rangeL], arr[rand() % (rangeR - rangeL + 1) + rangeL]);T temp = arr[rangeL];
int j = rangeL;//优化点:首先找出第一个大于arr[rangeL],从该值开始排序,能提升基本有序数组的排序效率
for (int i = rangeL + 1; i <= rangeR; i++) {
if (arr[i] >= temp) {
j = i - 1;
break;
}
}for (int i = rangeL + 1; i <= rangeR; i++) {
if (arr[i] < temp) {
j++;
swap(arr[i], arr[j]);
}
}swap(arr[j], arr[rangeL]);
return j;
}