快速排序

目录

快速排序

递归版本快速排序

三路快速排序

非递归/迭代法快速排序

稳定版本快速排序


快速排序

递归版本快速排序

#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] << " ";
    }

}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值