C++中sort和stable_sort的区别
- sort是快速排序实现,因此是不稳定的;stable_sort是归并排序实现,因此是稳定的;
- 对于相等的元素sort可能改变顺序,stable_sort保证排序后相等的元素次序不变;
Compare函数
分析源码,确定compare函数的用法
sort函数的两个重载:
template <class RandomAccessIterator>
inline void sort(RandomAccessIterator first, RandomAccessIterator last) {
if (first != last) {
__introsort_loop(first, last, value_type(first), __lg(last - first) * 2);
__final_insertion_sort(first, last);
}
}
template <class RandomAccessIterator, class Compare>
inline void sort(RandomAccessIterator first, RandomAccessIterator last,
Compare comp) {
if (first != last) {
__introsort_loop(first, last, value_type(first), __lg(last - first) * 2,
comp);
__final_insertion_sort(first, last, comp);
}
}
sort函数底层的一段源码:
template <class RandomAccessIterator, class T>
void __partial_sort(RandomAccessIterator first, RandomAccessIterator middle,
RandomAccessIterator last, T*) {
make_heap(first, middle);
for (RandomAccessIterator i = middle; i < last; ++i)
if (*i < *first)
__pop_heap(first, middle, i, T(*i), distance_type(first));
sort_heap(first, middle);
}
template <class RandomAccessIterator, class T, class Compare>
void __partial_sort(RandomAccessIterator first, RandomAccessIterator middle,
RandomAccessIterator last, T*, Compare comp) {
make_heap(first, middle, comp);
for (RandomAccessIterator i = middle; i < last; ++i)
if (comp(*i, *first))
__pop_heap(first, middle, i, T(*i), comp, distance_type(first));
sort_heap(first, middle, comp);
}
从以上源码可以看出来:
- sort的compare函数可以通过函数传参的方式传入
// struct less的仿函数
template <class T>
struct compare1 {
bool operator()(const T& x, const T& y) const { return x < y; }
};
// 或者
template <class T>
bool compare2(const T& x, const T& y) const { return x < y; }
*注意使用时的区别,compare1是一个struct类型,compare1()是一个struct compare1的对象。
而compare2是一个函数指针对象,而他的类型是bool (const T& x, const T& y)。
举个栗子:
std::vector<int> vector_test;
// 第一种写法
std::sort(vector_test.begin(), vector_test.end(), compare2<int>);
// 等价于
std::sort<std::vector<int>::iterator, bool(const int& a, const int& b)>(vector_test.begin(), vector_test.end(), compare2<int>);
std::sort<std::vector<int>::iterator, bool(*)(const int& a, const int& b)>(vector_test.begin(), vector_test.end(), compare2<int>);
// 等价于
std::sort<std::vector<int>::iterator, decltype(compare2<int>)>(vector_test.begin(), vector_test.end(), compare2<int>);
std::sort<std::vector<int>::iterator, bool(&)(const int& a, const int& b)>(vector_test.begin(), vector_test.end(), compare2<int>); // build error
// 第二种写法
std::sort(vector_test.begin(), vector_test.end(), compare1<int>());
等价于
std::sort<std::vector<int>::iterator, compare1<int>>(vector_test.begin(), vector_test.end(), compare1<int>());
- 如果没有显式地传入compare函数,则默认使用迭代器指示的元素的operator<函数
// 如果容器中的元素是下面这个struct element类型,则实现该类型的operator<函数。
// 从上面stl源码可以得知,如果没有传入compare函数,则默认调用元素的operator<。
struct element
{
bool operator<(const element& rhs)
{
return a < rhs.a;
}
int a;
};
sort适用场景
在SGI STL中根据读写和访问方式,在源码中迭代器大致可分为五类:
输入迭代器input_iterator: 只读,且只能一次读操作,支持操作:++p,p++,!=,==,=*p,p->;
输出迭代器output_iterator: 只写,且只能一次写操作,支持操作:++p,p++;
正向迭代器forward_iterator: 可多次读写,支持输入输出迭代器的所有操作;
双向迭代器bidirectional_iterator: 支持正向迭代器的所有操作,且支持操作:--p,--p;
随机访问迭代器random_access_iterator: 除了支持双向迭代器操作外,还支持:p[n],p+n,
n+p,p-n,p+=n,p-=n,p1-p2,p1<p2,p1>p2,p1>=p2,p1<=p2;
从sort源码定义可知,sort支持的类型应该是RandomAccessIterator,也即随机访问迭代器。
map,set,list显然都不支持RandomAccessIterator,而是bidirectional_iterator。所以sort不能直接用于对map,set的排序。
list有自己的成员sort方法。
queue本身的特性,queue没有迭代器。