Leetcode 912. 排序数组(快速排序实现)
题目描述:给你一个整数数组 nums,请你将该数组升序排列。
基本思想:通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。
中心思想:将比枢轴值小的放在左边,比枢轴值大的放在右边。
时间复杂度:
- 最优的情况下:复杂度为O(nlogn), 此时每次所选的枢轴值都能将待排序列均匀的划分成两部分。
- 最坏的情况下:复杂度为O(n^2),此时待排序列为正序或者逆序,每次划分只能得到一个比上一次少一个记录的子序列,另一个为空。这种时候无法达到二分的效果。
- 平均情况下:复杂度为O(nlogn),可以使用数学归纳法证明。
代码:
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
//拷贝数组,避免对原数组内容改变
vector<int> result(nums.size());
for (int i = 0; i < nums.size(); ++i) {
result[i] = nums[i];
}
Qsort(result, 0, result.size() - 1);//递归的调用
return result;
}
//对nums中子序列result[low, ..., high]作快速排序
void Qsort(vector<int>& result, int low, int high) {
if (low < high) {
int pivot = Partition(result, low, high);//将result[low, ..., high]一分为二,返回枢轴所在位置
Qsort(result, low, pivot - 1);//左半部分
Qsort(result, pivot + 1, high);//右半部分
}
}
//先选取一个值作为枢轴值,然后想尽办法将它放到一个位置,
//使得它左边的值都比他小,右边的值都比它大,最后返回该枢轴所在位置。
int Partition(vector<int>& result, int low, int high) {
int pivotkey = result[low];//取第一个元素作为枢轴值
while (low < high) {
//从result的两端交替向中间扫描
//整个过程要保证high指针后面的值都比枢轴值大;low指针前面的值都比枢轴值小
while (low < high && result[high] >= pivotkey) {
high--;
}
Swap(result, low, high);//将比枢轴值小的交换到低端
while (low < high && result[low] <= pivotkey) {
low++;
}
Swap(result, low, high);//将比枢轴值大的交换到高端
}
return low;//返回枢轴所在位置(最终时刻low和high指向同一个位置)
}
void Swap(vector<int>& result, int low, int high) {
int tmp = result[low];
result[low] = result[high];
result[high] = tmp;
}
};
下面是一个更加简洁的快排板子:
// 一个更加简洁的快排板子
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
vector<int> result(nums);
Qsort(result, 0, result.size() - 1);
return result;
}
void Qsort(vector<int>& result, int low, int high) {
if (low >= high) return;
int i = low - 1, j = high + 1, x = result[low + high >> 1];
while (i < j) {
do i++; while (result[i] < x);
do j--; while (result[j] > x);
if (i < j) swap(result[i], result[j]);
}
Qsort(result, low, j), Qsort(result, j + 1, high);
}
};