Files
CSCI-1200/lectures/15_maps_I/README.md
2023-10-19 00:52:26 -04:00

5.8 KiB
Raw Blame History

Lecture 15 --- Associative Containers (Maps), Part 1

Associative Containers (STL Maps)

  • STL Maps: associative containers for fast insert, access and remove
  • Example: Counting word occurrences
  • STL Pairs
  • Map iterators
  • Map member functions: operator[], find, insert, erase.
  • Efficiency
  • STL maps vs. STL vectors vs. STL lists

15.1 STL Maps: Associative Containers

  • STL maps store pairs of “associated” values. We will see several examples today, in Lab 9, and in Lecture 15:
  • An association between a string, representing a word, and an int representing the number of times that word has been seen in an input file.
  • An association between a string, representing a word, and a vector that stores the line numbers from a text file on which that string occurs (next lecture).
  • An association between a phone number and the name of the person with that number (Lab 9).
  • An association between a class object representing a student name and the students info (next lecture). A particular instance of a map is defined (declared) with the syntax: std::map<key_type, value_type> var_name In our first two examples above, key type is a string. In the first example, the value type is an int and in the second it is a std::vector<int>.
  • Entries in maps are pairs: std::pair<const key_type, value_type>
  • Map iterators refer to pairs.
  • Map search, insert and erase are all very fast: O(log n) time, where n is the number of pairs stored in the map. Note: The STL map type has similarities to the Python dictionary, Java HashMap, or a Perl hash, but the data structures are not the same. The organization, implementation, and performance is different. In a couple weeks well see an STL data structure that is even more similar to the Python dictionary.
  • Map search, insert and erase are O(log n). First, lets see how this some of this works with a program to count the occurrences of each word in a file. Well look at more details and more examples later.

15.2 Counting Word Occurrences

Heres a simple and elegant solution to this problem using a map:

#include <iostream>
#include <map>
#include <string>
int main() {
std::string s;
std::map<std::string, int> counters; // store each word and an associated counter
// read the input, keeping track of each word and how often we see it
while (std::cin >> s)
++counters[s];
// write the words and associated counts
std::map<std::string, int>::const_iterator it;
for (it = counters.begin(); it != counters.end(); ++it) {
std::cout << it->first << "\t" << it->second << std::endl;
}
return 0;
}

15.3 Maps: Uniqueness and Ordering

  • Maps are ordered by increasing value of the key. Therefore, there must be an operator< defined for the key.
  • Once a key and its value are entered in the map, the key cant be changed. It can only be erased (together with the associated value).
  • Duplicate keys can not be in the map.

15.4 STL Pairs

The mechanics of using std::pairs are relatively straightforward:

  • std::pairs are a templated struct with just two members, called first and second. Reminder: a struct is basically a wimpy class and in this course you arent allowed to create new structs. You should use classes instead.
  • To work with pairs, you must #include . Note that the header file for maps (#include ) itself includes utility, so you dont have to include utility explicitly when you use pairs with maps.
  • Here are simple examples of manipulating pairs:
std::pair<int, double> p1(5, 7.5);
std::pair<int, double> p2 = std::make_pair(8, 9.5);
p1.first = p2.first;
p2.second = 13.3;
std::cout << p1.first << " " << p1.second << std::endl;
std::cout << p2.first << " " << p2.second << std::endl;
p1 = p2;
std::pair<const std::string, double> p3 = std::make_pair(std::string("hello"), 3.5);
p3.second = -1.5;
// p3.first = std::string("illegal"); // (a)
// p1 = p3; // (b)
  • The function std::make pair creates a pair object from the given values. It is really just a simplified constructor, and as the example shows there are other ways of constructing pairs.
  • Most of the statements in the above code show accessing and changing values in pairs. The two statements at the end are commented out because they cause syntax errors:
  • In (a), the first entry of p3 is const, which means it cant be changed.
  • In (b), the two pairs are different types! Make sure you understand this.
  • Returning to maps, each entry in the map is a pair object of type: std::pair<const key_type, value_type>
  • The const is needed to ensure that the keys arent changed! This is crucial because maps are sorted by keys!

15.5 Maps: operator[]

  • Weve used the [] operator on vectors, which is conceptually very simple because vectors are just resizable arrays. Arrays and vectors are efficient random access data structures.
  • But operator[] is actually a function call, so it can do things that arent so simple too, for example: ++counters[s]; For maps, the [] operator searches the map for the pair containing the key (string) s. If such a pair containing the key is not there, the operator:
  1. creates a pair containing the key and a default initialized value,
  2. inserts the pair into the map in the appropriate position, and
  3. returns a reference to the value stored in this new pair (the second component of the pair). This second component may then be changed using operator++. If a pair containing the key is there, the operator simply returns a reference to the value in that pair.
  • In this particular example, the result in either case is that the ++ operator increments the value associated with string s (to 1 if the string wasnt already it a pair in the map).
  • For the user of the map, operator[] makes the map feel like a vector, except that indexing is based on a string (or any other key) instead of an int.
  • Note that the result of using [] is that the key is ALWAYS in the map afterwards.