一:起因
(1)java Map排序(key,value),请看另一篇博客 java Map排序
(2)c++ map排序(key,value),可以对c++ map和java Map进行对比:之一,c++的map默认按照key值进行排序,而且就是map了;java Map HashMap是随
机的,不进行排序的。之二,c++声明对象直接Map map(^)的,不用= new的
(3)c++ 按value值排序,map是不能直接排序的,它虽然也是一个数据集合,第一反应是利用stl中提供的sort算法实现,这个想法是好的,不幸的是,sort算法有个限制,利用sort算法只能对序列容器进行排序,就是线性的(如vector,list,deque)。map也是一个集合容器,但是它里面存储的元素是pair,它不是线性存储的(前面提过,像红黑树),所以利用sort不能直接和map结合进行排序。
(4) main函数中也可以实现函数重载,例如下面的 ostream& operator<<(ostream& out, const PAIR& p);还有就是定义的struct类(类似于class的)官方的说明见 (四)
(5) 按照value值进行排序:把值定义为一个结构体,包括你原本的值元素,还有键的值, 这样当你要按照值排序的时候,把map的值也就是结构体放
进vector中,剩下的按照你原来的值进行排序就行了。
这样是不行的,因为key是确定的,而value是可以改动的 如果按value自动排序的话map会变得极不稳定。你想,如果每次改变value整个map都要重新
排序的话不是性能损耗会很大吗?所以当初压根就没设计按照value排序的功能
二:代码实现
(1)先看pair类
template <class T1, class T2> struct pair { typedef T1 first_type; typedef T2 second_type; T1 first; T2 second; pair() : first(T1()), second(T2()) {} pair(const T1& x, const T2& y) : first(x), second(y) {} template <class U, class V> pair (const pair<U,V> &p) : first(p.first), second(p.second) { } }pair也是一个模板类,这样就实现了良好的通用性。它仅有两个数据成员first和second,即 key 和value,而且
(2)再看sort类
template <class RandomAccessIterator> void sort ( RandomAccessIterator first, RandomAccessIterator last ); template <class RandomAccessIterator, class Compare> void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );
(3)完整代码
#include<map> #include<string> #include<iostream> #include<vector> #include<algorithm> using namespace std; typedef pair<string, int> PAIR; // 原来还可以这样的重载的(⊙o⊙)哦,长见识了 ostream& operator<<(ostream& out, const PAIR& p) { return out << p.first << "\t" << p.second; } template<class T1> struct compareByKeyLen {// 从短到长 bool operator()(const T1 &s1,const T1 &s2) { return s1.length()<=s2.length()?true:false;// 记得有等号的哦,否则,长度相等的就舍去了 } }; template<class T1> struct compareByValue { bool operator()(const T1 &lhs, const T1 &rhs) { return lhs.second<=rhs.second ? true:false; } }; int main() { //map<string, int> name_score_map;//字典的顺序,从小到大 //默认的是map<string,int,less<string>> //map<string, int, greater<string> > name_score_map;// 注意> >有空格的,否则cin>>了; //字典的逆序,从大到小 //map<string, int, compareByKeyLen<string> > name_score_map; // 自己写的compareByKeyLen<>结构体 map<string, int> name_score_map; name_score_map["ZhaoBo2"] = 90; name_score_map["XuQingzhu"] = 79; name_score_map["LiBing"] = 92; name_score_map.insert(make_pair("ChiXiaotong",99)); name_score_map.insert(make_pair("WangZhaoxian",86)); vector<PAIR> name_score_vec(name_score_map.begin(),name_score_map.end()); sort(name_score_vec.begin(),name_score_vec.end(),compareByValue<PAIR>()); for(int i=0;i<name_score_vec.size();i++) { cout << name_score_vec[i] << endl; } // for (map<string, int>::iterator iter = name_score_map.begin(); // iter != name_score_map.end();++iter) // { // cout << *iter << endl; // } return 0; }(4)运行结果:
三:按key值排序(c++ map 带有比较类的,这和java一样,java也带有类似的比较类)
(1)compare类自己定义
比如,按照学生姓名的长短排序进行存储,那该怎么做呢?
其实很简单,只要我们自己写一个函数对象,实现想要的逻辑,定义map的时候把Compare指定为我们自己编写的这个就ok啦。
template<class T1> struct compareByKeyLen {// 从短到长 bool operator()(const T1 &s1,const T1 &s2) { return s1.length()<=s2.length()?true:false;// 记得有等号的哦,否则,长度相等的就舍去了 } };
是不是很简单!这里我们不用把它定义为模板,直接指定它的参数为string类型就可以了。
(2)参考代码
#include<map> #include<string> #include<iostream> using namespace std; typedef pair<string, int> PAIR; // 原来还可以这样的重载的(⊙o⊙)哦,长见识了 ostream& operator<<(ostream& out, const PAIR& p) { return out << p.first << "\t" << p.second; } template<class T1> struct compareByKeyLen {// 从短到长 bool operator()(const T1 &s1,const T1 &s2) { return s1.length()<=s2.length()?true:false;// 记得有等号的哦,否则,长度相等的就舍去了 } }; int main() { //map<string, int> name_score_map;//字典的顺序,从小到大 //默认的是map<string,int,less<string>> //map<string, int, greater<string> > name_score_map;// 注意> >有空格的,否则cin>>了; //字典的逆序,从大到小 map<string, int, compareByKeyLen > name_score_map; name_score_map["ZhaoBo"] = 90; name_score_map["XuQingzhu"] = 79; name_score_map["LiBing"] = 92; name_score_map.insert(make_pair("ChiXiaotong",99)); name_score_map.insert(make_pair("WangZhaoxian",86)); for (map<string, int>::iterator iter = name_score_map.begin(); iter != name_score_map.end();++iter) { cout << *iter << endl; } return 0; }
这一点有点类似java的map但是还是不一样的,感觉java倒是麻烦一些了。
四:从语法上,在C++中(只讨论C++中)。class和struct做类型定义时只有两点区别
从语法上,在C++中(只讨论C++中)。class和struct做类型定义时只有两点区别:
(一)默认继承权限。如果不明确指定,来自class的继承按照private继承处理,来自struct的继承按照public继承处理;
(二)成员的默认访问权限。class的成员默认是private权限,struct默认是public权限。
除了这两点,class和struct基本就是一个东西。语法上没有任何其它区别。
不能因为学过C就总觉得连C++中struct和class都区别很大,下面列举的说明可能比较无聊,因为struct和class本来就是基本一样的东西,无需多说。但这些说
明可能有助于澄清一些常见的关于struct和class的错误认识:
(1)都可以有成员函数;包括各类构造函数,析构函数,重载的运算符,友元类,友元结构,友元函数,虚函数,纯虚函数,静态函数;
(2)都可以有一大堆public/private/protected修饰符在里边;
(3)虽然这种风格不再被提倡,但语法上二者都可以使用大括号的方式初始化:Aa={1,2,3};不管A是个struct还是个class,前提是这个类/结构足够简单,比如所有的成员都是public的,所有的成员都是简单类型,没有显式声明的构造函数。
(4)都可以进行复杂的继承甚至多重继承,一个struct可以继承自一个class,反之亦可;一个struct可以同时继承5个class和5个struct,虽然这样做不太好。
(5)如果说class的设计需要注意OO的原则和风格,那么没任何理由说设计struct就不需要注意。
(6)再次说明,以上所有说法都是指在C++语言中,至于在C里的情况,C里是根本没有“class”,而C的struct从根本上也只是个包装数据的语法机制。
最后,作为语言的两个关键字,除去定义类型时有上述区别之外,另外还有一点点:“class”这个关键字还用于定义模板参数,就像“typename”。但关键字“struct”不用于定义模板参数。