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);