目录
快速排序
递归版本快速排序
#include <iostream>
#include <cstdio>
#include <ctime>
#include <cstdio>
using namespace std;
template <typename T>
int partition(T *a , int first, int last)
{
int last_small = first;
swap(a[first], a[(first+last)/2]);
T pivot = a[first];
for(int i = first+1; i <= last; i++){
if(a[i] < pivot){
++last_small;
swap(a[last_small], a[i]);
}
}
swap(a[first], a[last_small]); // swap with pivot
return last_small;
}
template<typename T>
void QuickSort(T *a, int first, int last){
if(last - first > 0){ //at least two element
int pivot_position = partition(a, first, last);
QuickSort(a, first, pivot_position-1);
QuickSort(a, pivot_position+1, last);
}
return;
}
#define MAXN 100
int a[MAXN];
int main()
{
for(int i = 0; i < MAXN; i++){
a[i] = MAXN-i;
}
QuickSort(a, 0, MAXN-1);
for(int i = 0; i < MAXN; i++){
cout << a[i] << endl;
}
return 0;
}
三路快速排序
如果待排序的数组中包含大量重复的元素,这种情况下,快排的性能就不那么理想了。我们改进之前的方法,将数组分为小于、等于和大于pivot的三部分。
int part(vector<int>& arr, int l, int r){
/*arr[lt] is the last element that less than pivot
arr[gt] is the first element that less than pivot
*/
int lt = l, gt = r+1; // less then & great then
int pivot = l; // can use random position as pivot
swap(arr[pivot], arr[l]);
for(int i = l+1; i < gt;){
if(arr[l] > arr[i]){
swap(arr[++lt], arr[i++]);
} else if(arr[l] < arr[i]){
swap(arr[i], arr[--gt]); // arr[i]位置通过交换得到的新元素,还要继续和pivot元素比较
} else{
++i;
}
} swap(arr[l], arr[lt]);
pivot = lt;
return pivot;
}
void qs(vector<int>& arr, int l, int r){
if(l >= r) return;
int pivot = part(arr, l, r);
qs(arr, l, pivot-1);
qs(arr, pivot+1, r);
}
void quick_sort(vector<int>& arr){
if(arr.size() <= 1) return;
qs(arr, 0, arr.size()-1);
return;
}
ref: https://blog.csdn.net/yjw123456/article/details/90081267
非递归/迭代法快速排序
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
// ref1: https://blog.csdn.net/pkuyjxu/article/details/6918295
// ref2: https://www.cnblogs.com/crystalmoore/p/5930298.html
void quick_sort(vector<int>& arr){
int n = arr.size();
if(n <= 1) return;
queue<pair<int, int> > q; // start & end
q.push(make_pair(0, n-1));
int s, e, last_small;
while(!q.empty()){
pair<int, int> p = q.front();
q.pop();
s = p.first, e = p.second, last_small = s;
if(s >= e) continue; // at least 2 elements
for(int i = s+1; i <= e; ++i){
if(arr[s] > arr[i]) swap(arr[++last_small], arr[i]);
} swap(arr[s], arr[last_small]); // pivot position is last_small
q.push(make_pair(s, last_small-1));
q.push(make_pair(last_small+1, e));
}
}
void print(vector<int> v){
for(int i = 0; i < v.size(); ++i){
cout << v[i] << ' ';
} cout << endl;
}
void check(vector<int> arr, void (*f)(vector<int>&) ){
vector<int> sorted_arr(arr.begin(), arr.end());
sort(sorted_arr.begin(), sorted_arr.end());
vector<int> v(arr.begin(), arr.end());
f(v);
if(sorted_arr.size() != v.size()){
cout << "sort failed: the element number is changed." << endl;
return;
}
for(int i = 1; i < v.size(); ++i){
if(v[i-1] > v[i]){
cout << "sort failed: not ordered." << endl;
return;
}
}
for(int i = 0; i < v.size(); ++i){
if(sorted_arr[i] != v[i]){
cout << "sort failed: element is change." << endl;
return;
}
}
cout << "sort succeed" << endl;
}
void test(){
int T = 100;
while(T--){
int n = 100, a[100];
for(int i = 0; i < n; ++i) a[i] = rand();
vector<int> v(a, a+n);
check(v, quick_sort);
}
return;
}
int main(){
test();
return 0;
}
稳定版本快速排序
上面的两个版本都是不稳定的快速排序,举例来说:
①如果通过 ≤ 将数组中的元素与pivot比较,把数组中的元素分隔开,我下面的代码执行结果:
初始:7^{a}, 7^{b}, 3, 6, 5, 9, 10. 已经是排好序的了,last_small等于4, 即在与pivot交换前,arr[last_small] = 5,
与pivot交换之后:5, 7^{b}, 3, 6, 7^{a}, 9, 10. 可以看出此时已经不是稳定的了
②如果通过 < 将数组中的元素与pivot比较,把数组中的元素分隔开,我下面的代码执行结果:
初始: 7^{a}, 7^{b}, 7^{c}, 3.
排序: 7^{a}, 3, 7^{c}, 7^{b}. 可以看出此时已经不是稳定的了
与pivot交换之后:3, 7^{a}, 7^{c}, 7^{b}.
下面的代码是改进的稳定版本快速排序,代码很简单:
// ref1: https://github.com/RodneyShag/HackerRank_solutions/blob/master/Algorithms/Sorting/Quicksort%202%20-%20Sorting/Solution.java
// ref2: https://www.geeksforgeeks.org/stable-quicksort/
int stable_partition(vector<int>& arr, int s, int e) {
if (s >= e) return s;
vector<int> left, right;
for(int i = s+1; i <= e; ++i){
if(arr[i] < arr[s]) left.push_back(arr[i]);
else right.push_back(arr[i]);
} int pivot_position = s+left.size();
arr[pivot_position] = arr[s]; // pivot
for(int i = 0, j = s; i < left.size(); ++i, ++j) arr[j] = left[i];
for(int i = 0, j = pivot_position+1; i < right.size(); ++i, j++) arr[j] = right[i];
return pivot_position;
}
void quick_sort(vector<int>& arr, int l, int r){
// assert(arr.size() > 1);
if(l >= r) return;
int pivot = stable_partition(arr, l, r);
quick_sort(arr, l, pivot-1);
quick_sort(arr, pivot+1, r);
}
每次要在`stable_partition`中创建`left`, `right`可能比较费时间,我个人会喜欢下面的实现,不过不太好理解了..
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int stable_partition(vector<int> &arr, int s, int e, vector<int>& tmp){
if (s >= e) return s;
int ts = s, te = e;
for(int i = s+1; i <= e; ++i){
if(arr[i] < arr[s]) // 用<比较, 可以保证arr[s]作为pivot时,排序后出现在所有值为arr[s]元素的最左(前)边. 同理,用≤比较时, pivot选择arr[e]可以保证跟arr[e]值相同的元素排在靠左(前)的位置, arr[e]排在右(后)边
tmp[ts++] = arr[i];
else tmp[te--] = arr[i]; // Note: 从右往左插入较大(≥)的值, 则先后顺序应该是靠右的元素出现的位置更靠前
} arr[ts] = arr[s]; // 放置pivot.
for(int i = s; i < ts; ++i) arr[i] = tmp[i]; // left: [s, ts)放置< pivot的元素,
for(int i = e, j = ts+1; i > te; --i, ++j) arr[j] = tmp[i]; // right: [ts+1, e]放置≥pivot的元素
return ts; // pivot position
}
void stable_qsort(vector<int> &arr, int s, int e, vector<int>& tmp){
if (s < e){
int p = stable_partition(arr, s, e, tmp);
stable_qsort(arr, s, p-1, tmp);
stable_qsort(arr, p+1, e, tmp);
}
}
void stable_quick_sort(vector<int> &arr){
if(arr.size() <= 1) return;
vector<int> tmp(arr.size());
stable_qsort(arr, 0, arr.size() - 1, tmp);
}
void check(vector<int> arr, void (*f)(vector<int>&) ){
vector<int> sorted_arr(arr.begin(), arr.end());
sort(sorted_arr.begin(), sorted_arr.end());
vector<int> v(arr.begin(), arr.end());
f(v);
if(sorted_arr.size() != v.size()){
cout << "sort failed: the element number is changed." << endl;
return;
}
for(int i = 1; i < v.size(); ++i){
if(v[i-1] > v[i]){
cout << "sort failed: not ordered." << endl;
return;
}
}
for(int i = 0; i < v.size(); ++i){
if(sorted_arr[i] != v[i]){
cout << "sort failed: element is change." << endl;
return;
}
}
cout << "sort succeed" << endl;
}
void test(){
int T = 100;
while(T--){
int n = 100, a[100];
for(int i = 0; i < n; ++i) a[i] = rand();
vector<int> v(a, a+n);
check(v, stable_quick_sort);
}
return;
}
int main()
{
test(); return 0;
vector<int> vec_nums{4, 8, 9, 1, 2, 3, 17, -1, 5, 4, 7, 6};//{1, 2, 3, 4};//{7, 8, 6, 9};//{4, 5, 1, 2};//{7, 8, 6, 9};//{ 4, 8, 9, 4, 7, 6};//{ 4, 8, 9, 5, 4, 7, 6};
stable_quick_sort(vec_nums);
for (int i = 0; i < vec_nums.size(); ++i)
{
cout << vec_nums[i] << " ";
}
}