1.问题描述
使用STL中partition和stable_partition来编写快速排序。
注意:关于STL中partition和stable_partition可以参考这里
2.分析
- 我们已经知道,partition和stable_partition是把一个容器按照第三个参数谓语分成两个部分。后者是稳定排序,不改变容器的相对位置,是一个稳定排序。
- 那么,这两个函数已经把快速排序中分类这一步完成了,我们只需要进行递归这一部分了。
3.源码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<typename T>
void printVec(T begin,T end)
{
for(auto iter = begin;iter !=end;++iter)
cout<<*iter<<" ";
cout<<endl;
}
template<typename T>
void m_stableSort(T begin,T end)
{
//递归的边界,如果只有一个元素就退出排序
if(end - begin <= 1)
return;
auto sz = *begin;
auto mid = std::stable_partition(begin,end,[sz](const int& value){ return value < sz;});
if(mid > begin)
m_stableSort(begin,mid);
if(mid < end -1)
m_stableSort(mid+1,end);
}
template<typename T>
void m_Sort(T begin,T end)
{
//递归的边界,如果只有一个元素就退出排序
if(end - begin <= 1)
return;
auto sz = *begin;
auto mid = std::partition(begin,end,[sz](const int& value){ return value < sz;});
//这里为什么需要交换mid和end-1这两个数?
//如果序列是 1,2,3,那么partition之后还是1,2,3,就不需要交换
//如果序列是 110,201,1,2,那么partition之后序列是,2,1,201,110,我们需要的中间值到尾部了,需要交换
if(*mid != sz)
std::swap(*mid,*(end-1));
if(mid > begin)
m_Sort(begin,mid);
if(mid < end -1)
m_Sort(mid+1,end);
}
int test08()
{
std::vector<int> numbers{102,44,99,35,201,110,1,2};
std::cout<<"print orige numbers:\n";
printVec(numbers);
std::cout<<std::endl;
m_stableSort(numbers.begin(),numbers.end());
std::cout<<"print after m_stableSort numbers:\n";
printVec(numbers);
std::cout<<std::endl;
return 0;
}
int test09()
{
std::vector<int> numbers{102,44,99,35,201,110,1,2};
std::cout<<"print orige numbers:\n";
printVec(numbers.begin(),numbers.end());
m_Sort(numbers.begin(),numbers.end());
std::cout<<"print after m_Sort numbers:\n";
printVec(numbers.begin(),numbers.end());
return 0;
}
int main()
{
test08();
test09();
return 0;
}
运行结果图:
4.结论
我们发现如果我们使用partition算法,必须要对分成的两部分再进行处理。如果可以把swap这部分去掉,会得到意想不到的结果。所以,我们最好使用stable_partition算法,毕竟稳定,可以避免一些麻烦。