[C + +] Some recommendations for efficient use of associative containers

Source: Internet
Author: User
Tags comparable

Associative containers

This article describes some of the issues that are common in associative containers and recommendations for promoting the use of associative containers.

1. Understand the difference between equality (equality) and equivalence (equivalence).

Equality is based on operator==. The equivalence is based on operator<.

For example, the definition of find is equal, and he uses operator== to judge, which is relatively easy to understand.

The equivalence relationship is based on the relative order of the object values in the sorted interval . That is, if any one of the two values (in accordance with the given order) is in front of the other, then they are equivalent.

    !(w1w2!(w2w1);    !c.key_comp()(xy!c.key.comp(yx);

key_comp()Returns a function that is passed in as X, y as a parameter.

Specifically, we envision a set that does not differentiate between string sizes to specify the problem.

#include <iostream>#include <set>#include <string>using namespace STD;BOOLCicharless (CharC1,CharC2) {//In C + +, char may be signed or unsigned, so we can compare it by converting it to unsigned char.     return ToLower(static_cast<unsigned Char> (C1) <ToLower(static_cast<unsigned Char> (C2));}BOOLCistringcompare (Const string& S1,Const string& S2) {returnLexicographical_compare (S1.begin (), S1.end (), S2.begin (), S2.end (), cicharless);}//It must is a struct but is not a class.structCistring: Publicbinary_function<string,string,BOOL> {BOOL operator() (Const string& T1,Const string& T2)Const{returnCistringcompare (T1, T2); }};intMainintargcChar*argv[]) { Set<string, cistring>Ciss//Ciss.insert ("Yan");Ciss.insert ("Yan"); Ciss.insert ("Yan"); Copy (Ciss.begin (), Ciss.end (), ostream_iterator<string> (cout,"\ n"));if(Ciss.find ("Yan")! = Ciss.end ()) {//base on equivalence.        cout<<"Find"<< Endl; }if(Find (Ciss.begin (), Ciss.end (),"Yan")! = Ciss.end ()) {//base on equality.        cout<<"Find, again!"<< Endl; }return 0;}/*yanfind*/

Did you find the problem when you saw the output? Also find, as a member function, find is based on equivalent comparison functions, and non-member functions are based on equal comparison functions, so they will have different results.

From a technical implementation standpoint, the types that define the operator = = operator belong to equality comparable. For example, all built-in types and pointer types in C + + are types under the equality comparable concept. C + + STL Find, Adjacent_find, find_first_of, search, Find_end, search_n, count, equal, mismatch, replace, replace_copy, Functions such as remove, remove_copy, unique, unique_copy, and so on, if overloaded, refer to a non-incoming function object version, require that the element type is equality comparable, which requires that the type be defined with the operator = = operator.
From a technical implementation perspective, the types that define the operator < operators belong to strict weakly comparable. For example, all built-in types and pointer types in C + + are types under the LessThan comparable concept. C + + STL Next_permutation, prev_permutation, Sort, stable_sort, Partial_sort, Partial_sort_copy, Nth_element, Binary_ Search, Lower_bound, Upper_bound, Equal_range, Merge, Inplace_merge, includes, Set_union, Set_intersection, set_ Difference, set_symmetric_difference, makde_heap, Push_heap, Pop_heap, Sort_heap, and so on (if overloaded, refer to non-incoming function object versions), and set, map, Multiset, Multimap, priority_queue and other container classes require that the element type belongs to strict weakly comparable, which requires that the type be defined with operator < operators.

Brief introduction of several common "comparison" concepts from C + + STL

2. Specify the comparison type for the associated container that contains the pointer

For associative containers that contain pointers, it is almost certain that you set the subclass of the comparison function yourself, otherwise unexpected results will occur. It is also important to note that the parameters for creating a container must be of type, not a function, so you must put a function object and let the STL call this function when it is implemented internally.

The right approach is given here directly. Memory leaks are not considered.

#include <iostream>#include <set>#include <string>using namespace STD;structCompare: Publicbinary_function<Const string*,Const string*,BOOL> {BOOL operator()(Const string* S1,Const string* S2) {return*s1 < *S2; }};intMainintargcChar*argv[]) { Set<string*, compare>S S.insert (New string("C")); S.insert (New string("B")); S.insert (New string("a"));return 0;}

Then, if you want to put the information output in the container in several different ways.

1. Use transform to convert the object in the container to a reference and output it to ostream_iterator.

struct Deference {    template<typename T>    constoperator()(constconst {        return *ptr;    }};    transform(s.begin(), s.end(), ostream_iterator<string>(cout"\n"), Deference());

2. Use the For_each function, and then use the anonymous function. Here I found that the original anonymous function can not use auto, otherwise, do not need to determine the type in the container.

    for_each(s.begin(), s.end(), [](string* s) {        cout << *s << endl;    });
3. Always let the object's comparison function return False when they are equal

This is a small detail, but it can cause a lot of problems.

For example, in set, each time the input compares the value to be entered is equivalent to the original value, so when the judgment is equal but gives true, then the element is inserted into the container, destroying the data structure in the container. Even in multiset, this can cause problems, for example, when calling Equal_range, incorrect results are given because of the comparison function.

So, if your view returns true for equal values in the comparison function, you break all the standard associative containers, regardless of whether it holds the same value.

4. Do not directly modify the keys in set or Muitiset

Note that the map and Muitimap are in many implementations where key is a const type and is not allowed to be modified, and if attempting to modify his key will directly result in non-portability. However, for set it is not so, he allows to be modified, but it must be noted that the key cannot be modified. The key in the set cannot be modified because each modification affects the entire set's arrangement structure.

For some implementations, the set key is indeed Const. If you have to change key, you can use the following methods.

#include <iostream>#include <set>#include <string>using namespace STD;classEmployee { Public:Const string& Name ()Const;voidSetNameConst string& name);Const string& Title ()Const;voidSettitle (Const string& title);};structNames: PublicBinary_function<employee, Employee,BOOL> {BOOL operator()(Constemployee& LHS,Constemployee& RHS)Const{returnLhs.name () < Rhs.name (); }};intMainintargcChar*argv[]) {typedef  Set<employee, names>Empset;    Empset se;    ...    Employee Selecttitle; Empset::iterator i = Se.find (selecttitle);if(I! = Se.end ()) {//I->setname (...); is non-portable.         const_cast<Employee&> (*i). SetName ("Yan"); }return 0;}

Here we set the set sort key, and try to change his key. The notation to be aware of const_cast<Employee&> (*i).setname("yan"); .

Turn him into a employee& by changing his const attribute. The reason is that if you just change him to Employee actually just get a copy of his object, it doesn't change his original object.

As for how to modify the key value of map. Actually very simple answer. Just delete the original pair and re-add a new pair with the key changed.

5. When efficiency is important, make a choice between map::operator[] and Map::insert

Map::operator[] and Map::insert can be used to update and insert new values, but there is a big difference in efficiency.

Simply put, map::operator[] is suitable for updating values. The reason is that

classWidget { Public: Widget () {cout<<"constructed!"<< Endl; } Widget (Doublei) {cout<<"Copy"<< Endl; } widget&operator=(Doublei) {cout<<"Pass"<< Endl;return* This; }};intMainintargcChar*argv[]) {typedef  map<int, widget>Intwidgetmap;    Intwidgetmap m; m[0] =1.4;return 0;}/*constructed!pass*/

This is actually achieved by:

classWidget { Public: Widget () {cout<<"constructed!"<< Endl; } Widget (Doublei) {cout<<"Copy"<< Endl; } widget&operator=(Doublei) {cout<<"Pass"<< Endl;return* This; }};intMainintargcChar*argv[]) {typedef  map<int, widget>Intwidgetmap;    Intwidgetmap m; Pair<intwidgetmap::iterator,BOOL> result = M.insert (Intwidgetmap::value_type (1, widgets ())); Result.first->second =1.50;return 0;}/*constructed!pass*/

The application of the Insert function is much more efficient. It is important to note that you must use Value_type. This is always some kind of pair.

int main(intchar *argv[]) {    typedefmap<int, Widget> IntWidgetMap;    IntWidgetMap m;    m.insert(IntWidgetMap::value_type(11.3));    return0;}/*copy*/

And for insertions, we always tend to apply operator[]. Compare their function calls to know.

#include <iostream>#include <map>using namespace STD;classWidget { Public: Widget () {cout<<"constructed!"<< Endl; } Widget (Doublei) {cout<<"Copy"<< Endl; } widget&operator=(Doublei) {cout<<"Pass"<< Endl;return* This; }};intMainintargcChar*argv[]) {typedef  map<int, widget>Intwidgetmap;    Intwidgetmap m; M.insert (Intwidgetmap::value_type (1,1.3));cout<< Endl; m[1] =1.5;cout<< Endl; M.insert (Intwidgetmap::value_type (1,1.5). First->second =Ten;return 0;}

[C + +] Some recommendations for efficient use of associative containers

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.