c++ 集合排序

std::sort vector string

我们先看一下 std::sort 的定义。头文件

template< class RandomIt >
void sort( RandomIt first, RandomIt last ); (1)

template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp ); (2)

Sorts the elements in the range [first, last) in non-descending order. The order of equal elements is not guaranteed to be preserved. 【即不稳定排序】
(1)式:Elements are compared using operator<.【默认使用operator<运算符比较】
(2)式:Elements are compared using the given binary comparison function comp.【使用comp比较元素大小】

关于 comp 参数:

The signature of the comparison function should be equivalent to the following: 
 bool cmp(const Type1 &a, const Type2 &b);

若第一参数小于(即先序于)第二参数则返回 ​true。cmp函数为bool类型,那么如果返回true,相当于不交换位置

复杂度:
平均 O(N·log(N)) 次比较,其中 N = std::distance(first, last)

例子:

#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
bool cmp(const int& a, const int& b) {
	return a > b;
}
int main()
{
	vector<int> arr = { 3,4,5,2,4,5,6 };
	// 1.
	// sort(arr.begin(), arr.end());
	
	// 2.
	//sort(arr.begin(), arr.end(), cmp);

	// 3. 使用 cpp 定义好的函数  #include <functional>
	//sort(arr.begin(), arr.end(), greater<int>());

	// 4. 使用自定义的类
	struct compare
	{
		bool operator()(int a, int b) const
		{
			return a > b;
		}
	};
	compare my_cmp;
	sort(arr.begin(), arr.end(), my_cmp);

	for (auto& item : arr)
		cout << item << ' '; 

	return 0;
}

map 排序

template < class Key,                                     // map::key_type
           class T,                                       // map::mapped_type
           class Compare = less<Key>,                     // map::key_compare
           class Alloc = allocator<pair<const Key,T> >    // map::allocator_type
           > class map;

可以看到 map 同 sort 一样,可以传入一个 Compare 类,缺省是 less 如下

template<class _Ty = void>
struct less
{	// functor for operator<
      constexpr bool operator()(const _Ty& _Left, const _Ty& _Right) const
      {	        // apply operator< to operands
		return (_Left < _Right);
       }
};

less 类是个模板类。里面是重载了 operator(),内部的比较是 operator< 实现的。所以如果我们想改变 map 的自动 key 排序方式,就可以传入自定义的比较类。

key 自定义排序

#include <map>
#include <string>
#include <iostream>
using namespace std;
struct Compare  // key 的排序 降序
{
	bool operator()(const string& s1, const string& s2) const
	{
		return s1 > s2;
	 }
};
int main()
{
	map<string, int, Compare> my_set;
	my_set.insert(make_pair(string("2dx"), 3));
	my_set[string("6dx")] = 7;
	my_set["3dx"] = 7;
	
	for (auto& item : my_set)
	{
		cout << item.first << ' ' << item.second << endl;
	}
	return 0;
}
6dx 7
3dx 7
2dx 3

按照value排序

我们知道 sort 函数只能对顺序容器如 vector, string 排序使用。所以,我们可以换个思路,将 map 先转入到 vecotr 中,再自定义按照 value 排序

#include <map>
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
 
typedef pair<string, int> PAIR;

struct 
{
	bool operator()(const PAIR& p1, const PAIR& p2)
	{
		// 按照 value 降序
		if (p2.second > p1.second)
			return true;
		else if (p2.second > p1.second)
			return false;
		else
		{
			// 按照 key 升序
			if (p1.first < p1.first)
				return true;
			else
				return false;
		}
	}
}Compare;
int main()
{
	map<string, int> my_map = {
		{"3th", 4}, {"2th", 7}, {"1th", 7}
	};

	vector<PAIR> my_vector;
	copy(my_map.begin(), my_map.end(), back_inserter(my_vector));

	sort(my_vector.begin(), my_vector.end(), Compare);

	for (auto& item : my_vector)
	{
		cout << item.first << ' ' << item.second << endl;
	}

	return 0;
}
3th 4
1th 7
2th 7

set 排序

set方式1 重载元素本身<运算符

但是对于 set map 等本身有序的函数,即在插入的时候,会通过比较元素选择插入的位置,所以我们可以通过重载 operator < 运算符实现自定义排序

#include <set>
#include <string>
#include <iostream>
using namespace std;
struct stu
{
	string name;
	int age;
	bool operator< (const stu& p) const // const必须写.
	{
		if (age < p.age)  // 按照 age 降序 
			return false;
		else if (age > p.age)
			return true;
		else
		{
			return name < p.name; // 否则, 按照 name 升序
		}
	}
};
int main()
{
	set<stu> my_set;
	stu s;
	my_set.insert(stu{ string("2dx"), 3 });
	my_set.insert(stu{ string("2dx"), 7 });
	my_set.insert(stu{ string("3dx"), 7 });
	
	for (auto& item : my_set)
	{
		cout << item.name << ' ' << item.age << endl;
	}
	return 0;
}
2dx 7
2dx 7
2dx 3

set 方式2 传入比较类

如果我们看 set 定义的方法

template<
    class Key,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<Key>
> class set;

可以看到其实 set 会有内置的比较方法,所以,除了对类方法进行重载,我们还可以传入一个比较函数。也就类似于 sort function 中的 cmp

#include <set>
#include <string>
#include <iostream>
using namespace std;
struct stu
{
	string name;
	int age;
};
struct Compare
{
	bool operator()(const stu& p1, const stu& p2)
	{
		if (p1.age < p2.age)  // 按照 age 降序 
			return false;
		else if (p1.age > p2.age)
			return true;
		else
		{
			return p1.name < p2.name; // 否则, 按照 name 升序
		}
	}
};
int main()
{
	set<stu, Compare> my_set;
	stu s;
	my_set.insert(stu{ string("2dx"), 3 });
	my_set.insert(stu{ string("2dx"), 7 });
	my_set.insert(stu{ string("3dx"), 7 });
	
	for (auto& item : my_set)
	{
		cout << item.name << ' ' << item.age << endl;
	}
	return 0;
}
2dx 7
3dx 7
2dx 3
posted @ 2021-03-02 19:18  孔胡子  阅读(521)  评论(0编辑  收藏  举报