STL中常见容器排序接口详解

一、sort算法

面试题:sort算法使用的是什么排序算法?稳定吗?

如果回答是快速排序,答案不完整,而且还会引来一下问题:

  1. 数据量大和数据量小都适合用快速排序吗?
  2. 快速排序的时间复杂度不是稳定的nlogn,最坏情况会变成n^2,怎么解决复杂度恶化问题?
  3. 快速排序递归实现时,怎么解决递归层次过深的问题?
  4. 递归过深会引发什么问题?
  5. 怎么控制递归深度?如果达到递归深度了还没排完序怎么办?

快速排序适合场景:数据越无序并且数据量越大,越能体现快速排序,而且如果数据是接近有序,快速排序会退化为冒泡排序。

问题解决:如果数据量小,那么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;
}

 

猜你喜欢

转载自blog.csdn.net/weixin_41318405/article/details/87904835