一、sort算法
面试题:sort算法使用的是什么排序算法?稳定吗?
如果回答是快速排序,答案不完整,而且还会引来一下问题:
- 数据量大和数据量小都适合用快速排序吗?
- 快速排序的时间复杂度不是稳定的nlogn,最坏情况会变成n^2,怎么解决复杂度恶化问题?
- 快速排序递归实现时,怎么解决递归层次过深的问题?
- 递归过深会引发什么问题?
- 怎么控制递归深度?如果达到递归深度了还没排完序怎么办?
快速排序适合场景:数据越无序并且数据量越大,越能体现快速排序,而且如果数据是接近有序,快速排序会退化为冒泡排序。
问题解决:如果数据量小,那么sort怎么应对?考虑到直接插入排序主要适用于数据量小和数据接近有序,所以sort算法内部除了快速排序,还嵌套了直接插入排序。
另外,数据量特别大,因为快速排序是递归版本,所以采用堆排序,防止递归路径过深,导致栈溢出。
综上所述,sort算法内部包括快速排序,直接插入排序和堆排序。执行步骤:先对数据分段,如果数据量过大,会调用堆排序。如果数据量小,会调用直接插入排序。并且sort排序是不稳定的,stable_sort是1稳定的排序。
sort函数内部默认是排升序,如下接口:
bool cmp(const int &left, const int &right)
{
return left > right;//此处是大于号
}
int main()
{
vector<int> v{ 3, 2, 5, 7, 1, 2, 9, 0, 4 };
sort(v.begin(), v.end());//默认升序
for (auto &e : v)
cout << e << " ";
cout << endl;
sort(v.begin(), v.end(), cmp);//自定义比较方式
for (auto &e : v)
cout << e << " ";
cout << endl;
return 0;
}
技巧:如果不知道降序,可以先排升序,然后reverse翻转。
二、list中sort
sort算法只能排序列式容器,所以list内部自己实现了sort排序。
struct cmp
{
bool operator()(const int &left, const int &right)
{
return left > right;//此处是大于
}
};
int main()
{
list<int> l{ 1, 2, 3, 6, 4, 2, 9, 9, 6, 2, 3, 0, 1 };
l.sort();//默认升序
for (auto&e : l)
cout << e << " ";
cout << endl;
l.sort(cmp());//调用自定义结构体实现降序,也可以reverse
for (auto&e : l)
cout << e << " ";
cout << endl;
return 0;
}
三、priority_queue
优先级队列内部实现是由vector和堆算法。堆的定义已经决定一系列关键码存储在数组当中,所以优先级队列底层容器采用vector。所以优先级队列默认实现大堆。我们需要调整为小堆,方法如下:
#include<functional>
struct cmp
{
bool operator()(const int& left, const int& right)
{
return left > right;//优先级队列大堆默认是小于,所以修改为大于
}
};
int main()
{
vector<int> v{ 2, 4, 1, 2, 7, 6, 9, 0 };
priority_queue<int> q(v.begin(), v.end());//默认小堆
//调整小堆方式
//方法一:greater,需要包含头文件#include<functional>
priority_queue<int, vector<int>, greater<int>> q1(v.begin(), v.end());
//方法二:仿函数:重载()
priority_queue<int, vector<int>, cmp> q2(v.begin(), v.end());
return 0;
}