diff --git a/lectures/15_maps_I/README.md b/lectures/15_maps_I/README.md new file mode 100644 index 0000000..66592a6 --- /dev/null +++ b/lectures/15_maps_I/README.md @@ -0,0 +1,117 @@ +# 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 student’s 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 we’ll see an STL data structure that is even more similar to the Python dictionary. +- Map search, insert and erase are O(log n). +First, let’s see how this some of this works with a program to count the occurrences of each word in a file. We’ll look +at more details and more examples later. + +## 15.2 Counting Word Occurrences + +Here’s a simple and elegant solution to this problem using a map: + +```cpp +#include +#include +#include +int main() { +std::string s; +std::map 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::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 can’t 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 aren’t 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 don’t have to include utility explicitly when you use pairs with maps. +- Here are simple examples of manipulating pairs: +```cpp +std::pair p1(5, 7.5); +std::pair 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 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 can’t 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 aren’t changed! This is crucial because maps are sorted by keys! + +## 15.5 Maps: operator[] + +- We’ve 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 aren’t 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 wasn’t 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.