1. 快速排序的流程
- 分组: 将序列分组,并保证该组的左端是小于主元的。自然地,右端要大于等于主元,然后返回主元的位置。这里选择一组中最右元素作为主元。这一过程使用双指针 i i i和 p o s pos pos实现,除了最后一步之外,指针 p o s pos pos始终指向右部的第一个元素,也就是指针 p o s pos pos左面的都是比主元小的元素。而指针 i i i负责不停地向右搜索比主元小的元素,并将其放到指针 p o s pos pos指向的位置。也就是将其和 p o s pos pos指向的元素交换位置。最后,将 p o s pos pos指向的元素和主元交换,也就是说,将主元放到右部的第一个位置上,从而保证了主元左部都是小于主元,而主元右部都是大于主元的。最终分组函数返回主元所在的位置下标。
- 递归:不停对主元的左右两端重复分组操作。
2. C++实现快速排序
程序注释很清楚,使用模板函数实现。
/**
* 使用模板函数实现一个快速排序
*/
#include <bits/stdc++.h>
using namespace std;
// 分组函数:升序排序保证左端元素小于主元,并返回主元位置
template <class T>
int partition(int left, int right, T& tar) {
int pos = left;
// 将left到right中小于主元的放到pos上
for (int i = left; i < right; ++i) {
if (tar[i] < tar[right]) { // 如果降序排序,则将 < 改为 > 。保证左端元素大于主元。
swap(tar[i], tar[pos]);
pos ++;
}
}
// 交换主元到中间,从而保证分组要求。
swap(tar[pos], tar[right]);
return pos;
}
// 快速排序,递归调用解决不同分组的排序问题
template <class T>
void qsort(int left, int right, T& tar) {
if (left >= right) return ;
int q = partition(left, right, tar);
qsort(left, q-1, tar);
qsort(q+1, right, tar);
}
主函数中测试样例:
int main() {
// vector<int> a{2,3,7,4,5,6,1,0};
// qsort<vector<int>>(0, a.size(), a);
// vector<char> a{'b', 'a', 'c', 'd'};
// qsort<vector<char>>(0, a.size()-1, a);
int a[7] = {3, 2, 1, 4, 5, 6, 7};
qsort<int[sizeof(a)/sizeof(int)]>(0, 6, a); // qsort<int[7]>(0, 6, a);
for (auto& e:a) {
cout << e << " ";
}
cout << endl;
}
总结
- 对于快速排序来说,其特点是递归的前进方向进行分组操作
- 而分组完成的任务是确定主元位置,以及保证主元的左部都是小于主元,而主元的右部都是大于主元。
- 从2.也可以得知,分组操作只能百分百保证排好一个元素的位置—主元。换句话说,一次分组操作中主元所处的位置就是最终排好序后的位置。
- 所以,需要分别对主元的左右两部再次进行分组操作,通过一次次分组操作,逐渐确定每一个主元的位置,直到最终分组中只剩下一个元素。而这个不断对主元左右两部进行分组的操作,正好可以通过递归实现。