Chapter XI related containers

Posted by jonwondering on Sun, 02 Jan 2022 07:33:20 +0100

The association container supports efficient lookup and access: map and set

map key Val: Dictionary

Each element in the set contains only one keyword. Set supports efficient keyword query operations

11.1 use of associated containers:

Use map:

map<string, size_t> word_count;
string word;
while(cin>> word){
    ++word_count[word];
}
for(const auto &w :word_count){
    //. operators, first and second are common data members
    //When you extract an element from the map, you get an object of type pair
    cout<<w.first<<"occurs" << w.second <<((w.second>1) ? " times":" time")<<endl;
}

Use set:

Ignore common words in the above program

map<string,size_t> word_count;
set<string> exclude = {"The","the","But","but"};

string word;
while(cin>>word){

    if(exclude.find(word)==exclude.end()){
            ++word_count[word];
    }
}

11.2 overview of associated containers

Iterators associated with containers are bidirectional.

11.2.1 defining associated containers

Initialize map and set

map<string,size_t> word_count;
set<string> exclude = {"the","but"};
map<string,string> authors = {
                              {"jon","avb"}
                              {"ss","avc"}                              
};

11.2.2 requirements for keyword type

By defau lt, the standard library uses the < operator of keyword type to compare two keywords. The keyword type in the collection is the element type, and the keyword type in the mapping type is the type of the first part of the element. For example, the keyword type in exclude is string, but word_ The keyword type of count is also string

When an ordered container defines its keyword, its keyword type must contain element comparison methods. If it is a class type and does not contain comparison methods, it is illegal and can define its own comparison type.

The callable object passed to the sorting algorithm must meet the same type requirements as the keyword in the associated container

Comparison function using keyword type:

We cannot define a sales directly_ Multiset of data because of the sales defined by yourself_ Data does not have the < operator, but you can use the compareIsbn function to define a multiset. So it's in sales_ A strict weak order is defined on the ISBN member of the data object.

bool compareIsbn(const Sales_data &lhs,const Sales_data &rhs){
    return lhs.isbn()<rhs.isbn();
}
//Multiple records in the bookstore can have the same ISBN
//The bookstore is sorted in the order of ISBN
multiset<Sales_data,decltype<compareIsbn>*> bookstore(compareIsbn);

11.2.3 pair type

       

pair<string,string> author{"Dwyane","wade"};

The data members of pair are all public

There are three ways to create pair s:

vec.push_back(std::make_pair(str, i));//make_pair returns a pair consisting of two parameters
vec.push_back({str, i});    //List initialization
vec.emplace_back(str, i); //Simplest

11.3 associated container operations

 

set<string>::value_type v1;            //string
set<string>::key_type v2;                //string
map<string,int>::value_type v3;         //pair<string,int>
map<string,int>::key_type v4;           //string
map<string,int>::mapped_type v5;        //int

11.3.1 associated container iterators

When dereferencing an associated container iterator, you will get a value of type container_ Reference to the value of type.

auto map_it = word_count.begin();
//*map_it, that is, when dereferencing, a pair < const key is returned_ value,mapped_ Type > returns a value_type
cout<< map_it->first;
cout<<" "<<map_it->second;
map_it->first = "new key";    //Error map_ It - > first is const    
++map_it->second;             //correct

The iterator for set is const

Only key in set_ Type, so the keyword in set is const. You can use a set iterator to read the value of an element, but you can't modify it.

set<int> iset ={0,1,2,3,4,5,6,7,8,9};
set<int>::iterator set_it = iset.begin();
if(set_it!=iset.end()){
    *set_it = 42;        //Error: keyword in set is read-only
    cout<<*set_it<<endl;    //Correct: you can read keywords
}

Traverse associated containers

auto map_it = word_count.cbegin();
while(map_it != word_count.cend()){

    cout<<map_it->first<< "+" <<map_it->second<<endl;
    ++map_it;
}
//When using an iterator to traverse a map multimap. When set or multiset, the iterator traverses the elements in ascending keyword order

Associated containers and algorithms

We usually don't use generic algorithms for associative containers because the keyword is const, the main feature.

The associated container can be used for algorithms for read-only elements. However, it is not suitable for generic algorithms. It is best to use a dedicated read-only algorithm defined by the associated container. For example, the find () generic algorithm is used to associate a map in a container find() works well.

In practical application, the association container mainly uses the algorithm as the source sequence or the target sequence.

11.3.2 adding elements

How to add elements to a map:

word_count.insert((word,1));                        //Simplest list initialization
word_count.insert(make_pair(word,1));
word_count.insert(pair<string,size_t>(word,1));
word_count.insert(map<string,size_t>::value_type(word,1));

Check the return value of insert:

The return value of insert (or replace) depends on the container type and parameters. For containers that do not duplicate keywords, insert and replace that add a single element return a pair < value_ Type:: iterator, bool >, if the keyword has been inserted in the container and does nothing, bool returns false. If the keyword does not exist, it is inserted and returns true.

map<string,size_t> word_count;
string word;
while(cin>>word){
    auto ret = word_count.insert({word,1});    //Note the type of ret at this time
    if(!ret.second){                           //ret<pair,bool>
          ++ret.first->second;                //You can understand this statement by knowing the return type
    }
}

Adding elements to a multiset or multimap

        

multimap<string,string> authors;
authors.insert({"Barth,Jonh","Sot-Weed Factor"});
authors.insert({"Barth,Jonh","Lost in the Funhouse"});
//For the multi insert function, the return value is an iterator pointing to the new element, and there is no need to return a bool value, because the insertion is always successful

11.3.3 deleting elements

The association container provides an additional erase operation and accepts a key_type parameter, delete all values matching the keyword, and return the number of elements actually deleted.
   

     if(word_count.erase(removal_word))
                cout<<"ok: "<<removal_word <<" removed\n";
     else cout<<"not found";

11.3.4 subscript operation of map

Only map can use subscripts, set does not support (key is value), and multimap is not one-to-one.

map<string,size_t> word_count;
word_count["Anna"] = 1;
//Search first
//If it exists, assign a value
//If it does not exist, it does not exist, and a new pair is created, where Anna is const string and the value is 0,
//Finally, set the value to 1

Return value using subscript operation

The subscript operator of map is different from other subscript operators in that generally, the type returned by dereferencing an iterator is the same as that returned by the subscript operator. But map is not. The map subscript operation returns mapped_type, and dereference to the map iterator returns a value_type object.

The same is that both return an lvalue:

11.3.5 access elements

     

Use find instead of subscript operation on map

Using subscript operation, when the element does not exist, it will be inserted by itself. If you do not want to insert, use find.

if(word_count.find("foobar") == word_count.end())
    cout<< "foobar is not in the map" <<endl;

Find elements in multimap and multiset

If multiple elements in a multimap or multiset have a given keyword, they are stored adjacent in the container.

string search_item("author_name");
auto entries = authors.count(search_item);
auto iter = authors.find(seach_name);        //Author returns first book
while(entries){
    cout<<iter->second <<endl;
    ++iter=;                                //Continuous storage
    --entries;
}

A different, iterator oriented solution

Call lower with the same keyword_ Bound and upper_bound gets an iterator range.

        lower_bound: returns the first of > =. upper_bound: returns the first of >

        lower_ The iterator returned by bound may point to an element with a given keyword, but lower if the keyword is not in the container_ Bound returns the first safe insertion point of the keyword -- the insertion position that does not affect the order of elements in the container.

If no element matches the given keyword, both lower and upper return equal iterators -- safe insertion points

for(auto beg =authors.lower_bound(search_item),
         end =authors.upper_bound(search_item);
       beg!=end; ++beg){

       cout<< beg->second<<endl;
}

equal_range function

        equal_ The range function receives a keyword and returns an iterator pair. The first iterator points to the first element matching the keyword and the second iterator points to the last. If not found, both iterators point to where keywords can be inserted.

       

for(auto pos = authors.equal_range(search_item);
         pos.first!=pos.second; ++pos.first   )
    cout<<pos.first->second <<endl;

This section mainly introduces three ways to access elements in multi. find,count,lower upper, equal——range

11.3.6 map of a word conversion

11.4 disordered containers

The new standard defines four unordered Association containers. These containers do not use comparison operators to organize elements, but use hash functions and keyword type = = operators.

Use unordered containers

unordered_map<string,size_t> word_count;
string word;
while(cin>>word){
    ++word_count["word"];
}
for(const auto &w: word_count){

    cout<<w.first<<w.second<<endl;
}

Management bucket

Unordered containers are a group of buckets in the storage organization, and each bucket holds 0 or more elements. Unordered containers use hash functions to map elements to buckets. When searching, find the bucket first, and then the element. The container stores all elements with a specific hash value in the same bucket.

Requirements of unordered containers for keyword types

By default, unordered functions compare elements using the keyword type = = operator. Also use hash < key_ Type > to generate the hash value of each element.

size_t hasher(const Sales_data &sd){
    return hash<string>()(sd.isbn());    //Use the standard library hash type object to calculate the hash value of ISBN members            
                                        //Type is based on string type.
}

bool eqOp(const Sales_data &lhs, const Sales_data &rhs){
    return lhs.isbn() == rhs.isbn();
}

using SD_multiset = unordered_multiset<Sales_data,decltype(hasher)*,decltype(eqOp)>;
//The parameters are bucket size, hash function pointer and equality judgment operator pointer.
SD_multiset bookstore(42,hasher,eqOp);