Sort by key for map in C + + STL and Sort by value

Source: Internet
Author: User

Sorting by key and sorting by value for map in C + + STL

Map is used to store <key, value> key value pairs of data structure, can be easily and quickly based on key to find the corresponding value. If you store students and their results (assuming that there are no duplicate names, of course, you can distinguish between names), we use map to store is a good choice. We define this, map<string, Int> where the student name is in string type, as key; The student's grade is in the int type, as value. In this way, we can quickly find his grades according to the student's name.

However, in addition to looking for a student's performance, we may also want to look at the overall situation. We want to lose all of our classmates and his results, and output them in the order we want them to be: in the order of the students ' names, for example, or according to the students ' grades. In other words, we want to be able to sort the map by key or sort by value, and then output the contents of its key-value pairs sequentially.

One, C + + STL map by Key sort

In fact, in order to achieve a quick lookup, the map itself is stored sequentially (such as red and black trees). When we insert <key, value> Key-value pairs, they are stored in the order of key size. This is also why the type of key must be able to perform a comparison of < operations. Now we use the string type as key, so our store is sorted by the dictionary of the student's name.

"Reference Code"

#include <map> #include <string> #include <iostream>using namespace std;typedef pair<string, int > pair;ostream& operator<< (ostream& out, const pair& p) {  return out << p.first << "\ T "<< P.second;} int main () {  map<string, int> name_score_map;  name_score_map["limin"] =;   name_score_map["Zilinmi"] =;   name_score_map["BoB"] =;   Name_score_map.insert (Make_pair ("Bing",));  Name_score_map.insert (Make_pair ("Albert", "the");  For (map<string, int>::iterator iter = Name_score_map.begin ();       Iter! = Name_score_map.end ();       ++iter) {    cout << *iter << endl;  }  return 0; }

"Run Results"

We all know that map is a template class inside STL, now let's look at the definition of map:

Template < class Key, class T, class Compare = Less<key>,           class Allocator = Allocator<pair<const key,t& Gt > > class map;


It has four parameters, of which we are more familiar with two: Key and Value. The fourth one is Allocator, which defines the storage allocation model, which we do not introduce here.

Now let's focus on the third parameter: Class Compare = less<key>

This is also a class type, and the default value of less<key> is provided. Less is a function object inside the STL, so what is a function object?

The so-called function object: the class that invokes the operator, whose objects are often called function objects, which are objects that behave like functions. The characteristic of a function is to use a class in the form of "object name + (parameter list)", which is essentially an overload of the operator () operator.

Now let's look at the implementation of less:

Template <class t> struct less:binary_function <T,T,bool> {  bool operator () (const t& x, const T& ; Y) const    {return x<y;}};


It is a struct with a template, only the () operator is overloaded, the implementation is very simple, but easy to use, which is the advantage of the function object. The STL also defines such a function object for common operations such as arithmetic, as opposed to less greater:

Template <class t> struct greater:binary_function <T,T,bool> {  bool operator () (const t& x, const t& Amp Y) const    {return x>y;}};


Map here specifies less as its default comparison function (object), so we usually do not specify the Compare,map in the key value pair will be in the order of the key to organize storage, so we see the above code output is based on the student name in the dictionary order output, That is, the less sequence of string.

We can specify a third parameter compare when we define the map, for example, we specify the default less as greater:

"Reference Code"

#include <map> #include <string> #include <iostream>using namespace std;typedef pair<string, int > pair;ostream& operator<< (ostream& out, const pair& p) {  return out << p.first << "\ T "<< P.second;} int main () {  map<string, int, greater<string> > name_score_map;  name_score_map["limin"] =;   name_score_map["Zilinmi"] =;   name_score_map["BoB"] =;   Name_score_map.insert (Make_pair ("Bing",));  Name_score_map.insert (Make_pair ("Albert", "the");  For (map<string, int>::iterator iter = Name_score_map.begin ();       Iter! = Name_score_map.end ();       ++iter) {    cout << *iter << endl;  }  return 0;}

"Run Results"

Now that we know how to specify the Compare class for map, if we want to write a compare class ourselves, let map store it in the order we want it, for example, to store it by the length of the student's name.

In fact, it is very simple, as long as we write a function object, to achieve the desired logic, define the map when the compare designated as our own writing this is OK.

struct Cmpbykeylength {  bool operator () (const string& K1, const string& K2) {    return k1.length () < K2.L Ength ();  }};

Isn't it simple! Here we do not need to define it as a template, directly specifying that its parameter is a string type is possible.

"Reference Code"

int main () {  map<string, int, cmpbykeylength> name_score_map;  name_score_map["limin"] =;   name_score_map["Zilinmi"] =;   name_score_map["BoB"] =;   Name_score_map.insert (Make_pair ("Bing",));  Name_score_map.insert (Make_pair ("Albert", "the");  For (map<string, int>::iterator iter = Name_score_map.begin ();       Iter! = Name_score_map.end ();       ++iter) {    cout << *iter << endl;  }  return 0;}

"Run Results"

Second, the C + + STL map by value Sort

In the first part, we use the parameter interface provided by map to specify the appropriate compare class for it, you can sort the map by key, and it is done in the process of creating a map and adding elements to it continuously.

Now we want to get students from the map from low to high order output, how to achieve it? In other words, how do you implement the map by value sort?

The first response is to use the sort algorithm provided in STL, which is good, unfortunately, the sort algorithm has a limit, using the sort algorithm can only order the sequence container, is linear (such as Vector,list,deque). Map is also a collection container, it is stored in the element is pair, but it is not linear storage (mentioned above, like a red black tree), so the use of sort can not be directly combined with the map to sort.

While it is not possible to sort the map directly with sort, can we make a detour by placing the elements in the map into a sequence container (such as a vector) and then sorting the elements? The idea seems to be workable. To sort the elements in a sequence container, there is also a requirement: the elements in the container must be comparable, that is, the < operation is implemented. So now we're going to look at the elements in the map to meet this condition?

We know that the element type in map is pair, which is defined as follows:

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 is also a template class, so that it achieves a good versatility. It has only two data members first and second, that is, key and value, and

In the <utility> header file, the < operator is also overloaded for pair, as follows:

  Template<class _t1, class _t2>,    inline bool    operator< (const PAIR<_T1, _t2>& __x, const pair <_T1, _t2>& __y)    {return __x.first < __y.first             | | (! (__y.first < __x.first) && __x.second < __y.second); }


Focus on its implementation:

__x.first < __y.first | | (! (__y.first < __x.first) && __x.second < __y.second)

This less in two cases returns true, the first case: __x.first < __y.first This good understanding is to compare key, if the __x key is smaller than the key of __y returns TRUE.

The second situation is a little confusing:! (__y.first < __x.first) && __x.second < __y.second

Of course due to | | The operation has a short-circuit effect, that is, the condition of the current plane is not satisfied, only then the second case is judged. The first case __x.first < __y.first is not established, namely __x.first >= __y.first was established, under this condition, we come to analyze! (__y.first < __x.first) && __x.second < __y.second

! (__y.first < __x.first), see, here is the key of Y is not less than X key, combined with the precondition, __x.first < __y.first is not established, that is, X key is not less than the key of Y

That is:! (__y.first < __x.first) &&! (__x.first < __y.first) is equivalent to __x.first = = __y.first, that is, the second case is to compare the value (second) of both in the case of key equality.

The more puzzling part here is, why not directly write __x.first = = __y.first it? This may seem puzzling, but in fact, it is not unreasonable: as a key to the map must implement the < operator overload, but there is no guarantee that the = = character is overloaded, if key does not provide = =, then, __x.first = = __y.first This write is wrong. Thus, the code in the STL is quite rigorous and deserves a good reading.

Now we know that the pair class overloads the < character, but it is not compared by value, but rather the key is compared first, and key is equal to value. It is not clear that we need to sort by value.

Moreover, since the pair has overloaded the < character, and we cannot modify its implementation, we cannot repeatedly implement the overloaded < character externally.

typedef pair<string, int> pair;bool operator< (const pair& LHS, const pair& RHS) {    return Lhs.second < Rhs.second;}


If the pair class itself is not overloaded with <, then we can use the above code overload < to achieve the comparison of the pair by value. Now this does not work, even error (compiler different, strict error).

So how do we compare pair by value? The first kind: is the most primitive method, write a comparison function, the second kind: just used, write a function object. Both of these approaches are relatively simple to implement.

typedef pair<string, int> pair;bool cmp_by_value (const pair& LHS, const pair& RHS) {  return Lhs.second & Lt Rhs.second;} struct Cmpbyvalue {  bool operator () (const pair& LHS, const pair& RHS) {    return Lhs.second < Rhs.second;  }};


Next, let's look at the sort algorithm, is it also like map, can we specify how to compare between the elements?

Template <class randomaccessiterator>  void sort (randomaccessiterator first, Randomaccessiterator last); Template <class Randomaccessiterator, class compare>  void Sort (randomaccessiterator first, Randomaccessiterator last, Compare comp);

As we can see, it is exciting that the sort algorithm, like map, allows us to specify how the elements are compared, specifying compare. It is important to note that the map is specified at the time of definition, so the parameter is passed directly to the class name of the function object, just like the type name specified when the key and value are specified, the sort algorithm is specified at invocation, it needs to pass in an object, and of course, the class name () calls the constructor to generate the object.

It is also possible to pass in a function pointer, which is the function name of the first method mentioned above. (should be there is a function pointer to the function object conversion, or the two call form is consistent, the exact reason still do not understand, want to know the friend to speak, first thank you. )

"Reference Code"

int main () {  map<string, int> name_score_map;  name_score_map["limin"] =;  name_score_map["Zilinmi"] =;  name_score_map["BoB"] =;  Name_score_map.insert (Make_pair ("Bing",));  Name_score_map.insert (Make_pair ("Albert", 86)); Dump the elements in the map into the vector   vector<pair> Name_score_vec (Name_score_map.begin (), Name_score_map.end ());  Sort (Name_score_vec.begin (), Name_score_vec.end (), Cmpbyvalue ()); Sort (Name_score_vec.begin (), Name_score_vec.end (), cmp_by_value);  for (int i = 0; I! = Name_score_vec.size (); ++i) {    cout << name_score_vec[i] << Endl;  }  return 0;}

"Run Results"



  original articles, reproduced please specify: reproduced from    iicyzhao ' s Road

          This article link address:  http://blog.csdn.net/iicy266/article/details/11906189

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.