据说是21世纪算法界最大的发明
快速排序
基本思路
单路快排
下图是一个快速排序的例子,排序过程中将数组分成两端,[l+1...j]<=v,[j+1...i-1]>v。j的初始值 j=l,所以循环不变量成立。
实现代码如下:
#include <stdio.h>
#include <vector>
#include <cstdlib>
#include <time.h>
using namespace std;
class QuickSort {
public:
void sort(vector<int>& arr) {
int size = (int)arr.size();
sort(arr, 0, size);
}
void sort(vector<int>& arr, int i,int j) {
int index = partition(arr, i, j);
if (index <= 0 || index > j-1) {
return;
}
sort(arr, 0, index);
sort(arr, index+1, j);
}
int partition(vector<int>& arr, int l, int r) {
srand((unsigned)time(NULL));
int randNum = l+(r-l-1)/2;
/// j 指向数组中小于第一个元素的最后一个索引
int j = l;
/// 交换元素
swap(arr, randNum, j);
/// 循环不变量:[l+1...j] <= v, [j+1...i-1] > v
for (int i = l+1; i < r; i++) {
if (arr[i] <= arr[l]) {
swap(arr, i, j+1);
j++;
}
}
/// 循环结束时,将第一个元素和t位置的元素交换
swap(arr, l, j);
return j;
}
void swap(vector<int>& arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
};
容易出错的地方:
-
sort(arr, 0, index) 写成了 sort(arr, 0, index-1),实际在 partition 中,不会处理右边界的元素
-
int randNum = i+(j-i-1)/2 写成了 int randNum = (j-i-1)/2,这样算出来的数比较小,会把已排序的元素直接给交换了 注意事项
-
partition中函数入参,最好写成l,r,这样比较贴切,因为递归排序的内容不确定坐标,只知道起始位置,结束为止
双路快排
基本思路:前面的元素遇到比v大的元素停下,后面的元素遇到小于等于v的元素停下,如果此时 j>i,则交换元素。
交换元素后,在循环外面一定注意把第一个元素和j位置的元素进行交换。
为什么需要双路快速排序?是因为当有大量重复元素时,单路快排的时间复杂度会退化成O(n^2)
实现代码如下:
#include <stdio.h>
#include <vector>
#include <cstdlib>
#include <time.h>
using namespace std;
class QuickSortExe {
public:
void sort(vector<int>& arr) {
int size = (int)arr.size();
sort(arr, 0, size-1);
}
void sort(vector<int>& arr, int l,int r) {
if (l>=r) {
return;
}
int index = partition2(arr, l, r);
sort(arr, 0, index-1);
sort(arr, index+1, r);
}
/// 双路快排
int partition2(vector<int>& arr, int l, int r) {
int randNum = l + (r-l)/2;
swap(arr, l, randNum);
int i = l + 1;
int j = r;
while (true) {
/// i<=j 也可以替换成 i<=r、i<arr.size
while (i<=j && arr[i] < arr[l]) {
i++;
}
/// 看到有不同风格的写法:j>=i && arr[j] > arr[l],实际上 j>=i 可以不要
while (arr[j] > arr[l]) {
j--;
}
/// 这里要=是因为,最后剩余的一个元素正好等于v,则结束,在循环外层进行交换
if (i>=j) {
break;
}
swap(arr, i, j);
i++;
j--;
}
swap(arr, l, j);
return j;
}
void swap(vector<int>& arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
};
三路快排
(待实现)