C++ STL: map的按key和按value排序

相关内容: C++ STL: map自定义键值类型C++ 函数对象(函数符)

本文目录

1. map定义

在将map的排序之前,我们要知道它是STL里的一个模板类,用来存放<key, value>键值对的数据结构,定义如下。

template < class Key,                                   //map::key_tpe
           class T,                                     //map::mapped_type
           class Compare = less<Key>,                   //map::key_compare
           class Alloc = allocator<pair<const Key, T>>  //map::allocator_type
           > class map;
  • 第1个参数存储了key。

  • 第2个参数存储了mapped value。

  • 第3个参数是比较函数的函数对象。map用它来判断两个key的大小,并返回bool类型的结果。利用这个函数,map可以确定元素在容器中遵循的顺序以及两个元素键是否相等(!comp(a,b)&&!comp(b,a)),确保map中没有两个元素可以具有等效键。这里,它的默认值是less<Key>,定义如下。

    template <class T> 
    struct less {
      bool operator() (const T& x, const T& y) const {return x < y;}
      typedef T first_argument_type;
      typedef T second_argument_type;
      typedef bool result_type;
    };
    
  • 第4个参数是用来定义存储分配模型的。

2. 按key排序

实际上map内部所有的数据本来就是按key排序的。分析map结构定义,发现map的按key排序是通过第3个参数(比较函数的函数对象)实现的。

其中,less为其默认的函数对象,所以如果我们不指定参数3,map键值对就会按照默认方法进行存储。当我们希望它能以不同的方式进行排序,就需要重新指定参数3。

如果只是调用C++标准库自带的方法,我们只需如下所示,在声明map对象时指定第3参数即可。

#include <iostream>
#include <map>
#include <string>
using namespace std;

int main(){
	map<string, int, greater<string>> test; //指定参数3为greater<string>
	test["Alice"] = 3;
	test["Cindy"] = 11;
	test["Bob"] = 7;

	for(auto itr = test.begin(); itr != test.end(); ++itr){
		cout << itr->first << ": " << itr->second << endl;
	}
	return 0;
}

然而,当我们自定义map的键值类型时,C++标准库往往没有对应的函数对象可供使用,这时候,我们就需要自定义函数对象了。关于方法,我在C++ STL: map自定义键值类型这篇文章里讲得非常详细,文中提出了针对自定义键值排序的4种方法。

3. 按value排序

对value的排序,我查了很多资料,主要有以下两个思路。

  • 一是通过将map转换到序列容器,再用STL提供的sort方法得以实现的。

  • 二是通过将map的key和value位置替换

3.1 通过序列容器调用sort

为什么我们不能直接用sort给map排序呢?

这是因为sort算法只能对序列容器进行排序,就是线性的(如vector,list,deque)。map虽然也是一个集合容器,但是它不是线性存储的(比如红黑树)。因此,我们需要先把map中的元素放到序列容器中,然后再对这些元素进行排序。

根据定义,sort算法的第3个参数即可以是函数指针,也可以是函数对象(可以以函数方式与()结合使用的任意对象,包括函数名、指向函数的指针和重载了“operator()”操作符的类对象)。

下面的算法,给出了函数对象的两种情况。

#include <iostream>
#include <map>
#include <vector>
#include <string>
using namespace std;

typedef pair<string, int> Pair;

//第3参数为函数名
bool my_compare(const Pair &p1, const Pair &p2){
	return p1.second < p2.second;
}

//第3参数为重载了operator()操作符的类对象
struct MyCompare{
public:
	bool operator()(const Pair &p1, const Pair &p2) const{
		return p1.second < p2.second;
	}
};

int main(){
	map<string, int> test;
	test["Alice"] = 3;
	test["Cindy"] = 5;
	test["Bob"] = 7;

	cout << "> sort by key" << endl;
	for(auto itr = test.begin(); itr != test.end(); ++itr){
		cout << itr->first << ": " << itr->second << endl;
	}
	cout << endl;

	vector<Pair> vec;

	for(auto itr = test.begin(); itr != test.end(); ++itr){
		vec.push_back(make_pair(itr->first, itr->second));
	}

	sort(vec.begin(), vec.end(), MyCompare()); //my_compare或者MyCompare()都可以

	cout << "> sort by value" << endl;
	for(auto itr = vec.begin(); itr != vec.end(); ++itr){
		cout << itr->first << ": " << itr->second << endl;
	}

	return 0;
}

【结果】

> sort by key
Alice: 3
Bob: 7
Cindy: 5

> sort by value
Alice: 3
Cindy: 5
Bob: 7

3.2 替换map的key和value

方法2通过std::transform实现替换,下面是transform的定义。

//一元操作
template <class InputIterator, class OutputIterator, class UnaryOperation>
OutputIterator transform (InputIterator first1, InputIterator last1,
                          OutputIterator result, UnaryOperation op);
//二元操作
template <class InputIterator1, class InputIterator2,
          class OutputIterator, class BinaryOperation>
OutputIterator transform (InputIterator1 first1, InputIterator1 last1,
                          InputIterator2 first2, OutputIterator result,
                          BinaryOperation binary_op);

对于一元操作,op将应用于[first1, last1]范围内的每个元素,并将每个操作返回的值存储在以result开头的范围内。给定的op将被连续调用last1-first1+1次。op可以是函数指针或函数对象或lambda表达式。二元操作,本文不会用到,这里不做说明。

因此,基于上面的定义,我们的程序如下所示。

#include <iostream>
#include <map>
#include <vector>
#include <string>
using namespace std;

typedef pair<string, int> Pair;

int main(){
	map<string, int> test;
	test["Alice"] = 3;
	test["Cindy"] = 5;
	test["Bob"] = 7;

	cout << "> sort by key" << endl;
	for(auto itr = test.begin(); itr != test.end(); ++itr){
		cout << itr->first << ": " << itr->second << endl;
	}
	cout << endl;

	map<int, string> result;
	transform(test.begin(), test.end(), inserter(result, result.begin()), [](pair<string, int> a) { return pair<int, string>(a.second, a.first); });
	
	cout << "> sort by value" << endl;
	for(auto itr = result.begin(); itr != result.end(); ++itr){
		cout << itr->first << ": " << itr->second << endl;
	}

	return 0;
}

【结果】

> sort by key
Alice: 3
Bob: 7
Cindy: 5

> sort by value
3: Alice
5: Cindy
7: Bob

4. 参考链接

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值