作为最常用的三大排序方法,必须掌握。这里给出递归写法C++实现,相比迭代写法会更容易理解。
代码实现
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
void SortArr(vector<int>& nums) {
//quickSort(nums, 0, nums.size() - 1);
//mergeSort(nums, 0, nums.size() - 1);
heapSort(nums);
}
private:
void quickSort(vector<int>& nums, int l, int r) {
if (l < r) {
int pos = partition2(nums, l, r);
quickSort(nums, l, pos - 1);
quickSort(nums, pos + 1, r);
}
}
// 以pivot分隔,选最左为pivot
// 第一种Partition方式,对撞指针法
int partition(vector<int>& nums, int l, int r) {
// 随机化加速,抑制最坏时间复杂度
int i = rand() % (r - l + 1) + l;
swap(nums[i], nums[l]);
int pivot = nums[l];
while (l < r) {
// 右侧第一个小于pivot的元素
while (l < r && nums[r] >= pivot) --r;
nums[l] = nums[r];
// 左侧第一个大于pivot的元素
while (l < r && nums[l] <= pivot) ++l;
nums[r] = nums[l];
}
nums[l] = pivot;
return l;
}
// 第二种Partition方式,快慢指针法
int partition2(vector<int>& nums, int l, int r) {
// 随机化加速,抑制最坏时间复杂度
int tmp = rand() % (r - l + 1) + l;
swap(nums[tmp], nums[l]);
int pivot = nums[l];
int i = l + 1;
for (int j = l + 1; j <= r; ++j) {
if (nums[j] <= pivot) {
swap(nums[i], nums[j]);
++i;
}
}
swap(nums[i-1], nums[l]);
return i-1;
}
void mergeSort(vector<int>& nums, int l, int r) {
if (l == r) return;
// 分解
int mid = l + (r - l) / 2;
mergeSort(nums, l, mid);
mergeSort(nums, mid + 1, r);
// 合并
int i = l, j = mid + 1, pos = 0;
vector<int> tmp(r - l + 1); // 合并时需要辅助数组
while (i <= mid && j <= r) {
tmp[pos++] = nums[i] <= nums[j] ? nums[i++] : nums[j++];
}
// 还有剩余
while (i <= mid) {
tmp[pos++] = nums[i++];
}
while (j <= r) {
tmp[pos++] = nums[j++];
}
copy(tmp.begin(), tmp.end(), nums.begin() + l);
}
void heapSort(vector<int>& vec) {
int sz = vec.size();
// S1.建大顶堆
// sz/2-1是最后一个非叶子节点
for (int i = sz / 2 - 1; i >= 0; --i) {
down(vec, i, sz);
}
// S2.大顶堆一个一个把最大的移到末尾
for (int i = sz - 1; i > 0; --i) {
swap(vec[0], vec[i]); // 把最大的移到末尾
down(vec, 0, i); // 维持大顶堆,只需调整i=0,注意sz变为了i
}
}
void down(vector<int> &vec, int i, int sz) {
// 核心就是找i和其lSon、rSon三者最大的换到i的位置
int lSon = i * 2 + 1;
int rSon = i * 2 + 2;
int maxIdx = i;
if (lSon < sz && vec[lSon] > vec[maxIdx]) maxIdx = lSon;
if (rSon < sz && vec[rSon] > vec[maxIdx]) maxIdx = rSon;
if (maxIdx != i) {
swap(vec[i], vec[maxIdx]);
down(vec, maxIdx, sz);
}
}
};
int main() {
Solution sln = Solution();
vector<int> nums = { 1, 3, 5, 2, 2, 6 };
sln.SortArr(nums);
for (int num : nums) {
cout << num << ' ';
}
return 0;
}
快排本身有劣势,数字一样变n方。
实现思路可参考: