Associative Containers in C++
Associative containers support efficient lookup and access by key. The two primary associative containers are set and map. The elements of a map are key-value pairs, where the key acts as an index and the value represents the data associated with that index; the elements of a set contain only a key. A set supports efficient key lookup, and is presumably implemented with a hash table under the hood.
The C++ standard library provides 8 associative containers, and these 8 containers differ along three dimensions:
- set or map
- ordered or unordered---whether there is an unordered prefix
- duplicate keys allowed or forbidden---whether there is a multi prefix
This article focuses on set and map; for content related to the other containers, refer to the C++ API.
Using set and map
Using a map:
//count how many times each word appears in the input
map<string,size_t> word_count; //create a new map
string word;
while(cin>>word)
++word_count[word]; //increment the count for this word by 1
for(const auto &w:word_count)
cout<<w.first<<" occurs "<<w.second<<((w.second>1)?" times":" time")<<endl;
Note that for the subscript operation on a map, if you use word_count[word], then when the key word is not found, an element with key word is added and its value is value-initialized. If you use word_count.at(word), then when the key word is not found, an out_of_range exception is thrown.
Using a set:
//count how many times each word appears in the input
map<string,size_t> word_count;
set<string> exclude={"The","But","And","Or","An"};
string word;
while(cin>>word)
if(exclude.find(word)==exclude.end()) //when the word is not found in the set, find returns the end iterator
++word_count[word];
The pair class and the extra type aliases in associative containers
The pair class is defined in the header utility, and a pair holds two data members. Like the containers, pair is a template used to generate specific types. When creating a pair, we must supply two type names.
pair<string,size_t> word_count; //holds a string and a size_t
Unlike the other standard library types, the data members of a pair are public; the two members are named first and second respectively, and the elements stored in a map are exactly of pair type.
Associative containers also define other types that represent the types of the container’s keys and values:
- key_type the container’s key type
- mapped_type the type associated with each key, applicable only to map
- value_type for set, the same as key_type; for map, it is
pair<const key_type,mapped_type>
set<string>::value_type v1; //string
set<string>::key_type v2; //string
map<string,int>::value_type v3; //pair<const string,int>
map<string,int>::key_type v4; //string
map<string,int>::mapped_type v5;//int
Iterators of associative containers
When you dereference an iterator of an associative container, you get a reference to a value of the container’s value_type. For a map, value_type is a pair type whose first member holds the const key and whose second member holds the value:
//obtain an iterator to an element in word_count
auto map_it=word_count.begin();
//*map_it is a reference to a pair<const string,size_t> object
cout<<map_it->first;
cout<<" "<<map_it->second;
map_it->first="new key"; //error, the key is const
++map_it->second; //the value element can be changed
The keys in a set are also const. You can use a set to read element values, but you cannot modify them:
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, a const key cannot be modified
cout<<*set_it<<endl;
}