Answers to exercises in section 10.3 of Chapter 11 of C++ Primer

Chapter 11 Association container of C++ Primer

Section 10.3 answers to related container operation exercises

Exercise 11.16: write an expression using a map iterator to assign a value to an element.

[Topic setting ideas]

Understand the type of iterator dereference of map.

[answer]

Dereference the iterator of the associated container and get value_ Reference to the value of type. Therefore, for a map, what you get is a reference of pair type. The first member holds the keyword of const and the second member holds the value. Therefore, the iterator can only modify the value, not the keyword.

#include <iostream>
#include <map>

using namespace std;

int main()
{
    map<int, int> m;
    m[1] = 10;
    auto it = m.begin();
    for(auto temp: m)
        cout << "temp.first=" << temp.first << " temp.second=" << temp.second << endl;

    it->second = 20;
    for(auto temp: m)
        cout << "temp.first=" << temp.first << " temp.second=" << temp.second << endl;

    cout << m.size() << endl;

    return 0;
}

Operation results:

Exercise 11.17: assuming that c is a multiset of a string and v is a vector of a string, explain the following call. Indicate whether each call is legal:

copy(v.begin(), v.end(), inserter(c, c.end()));
copy(v.begin(), v.end(), back_inserter(c));
copy(c.begin(), c.end(), inserter(v, v.end()));
copy(c.begin(), c.end(), back_inserter(v));

[Topic setting ideas]

Understand the characteristics of set iterators.

[answer]

The iterator of set is const, so only the elements in set are allowed to be accessed, and set cannot be changed. Like map, the keyword of set is const, so you can't change the value of elements in set through iterators.

Therefore, the first two calls attempt to copy the elements in the vector into the set,

It's illegal. It is legal for the latter two calls to copy the elements in the set into the vector.

Exercise 11.18: write the map in the loop on page 382_ It type, do not use auto or decltype.

[Topic setting ideas]

Understand map iterators.

[answer]

*map_it refers to a pair < const string, size_ t> Object.

  So map_ The type of it is pair < const string, size_ t>::iterator

  Exercise 11.19: define a variable and initialize it by calling begin() on a multiset named bookstore in section 11.2.2 (page 378). Write out the type of the variable. Do not use auto or decltype.

[Topic setting ideas]

This topic continues to practice iterators associated with containers.

[answer]

typedef bool (*pf)(const Sales_data &, const Sales_data &);
multiset<Sales_data, pf> bookstore(compareIsbn);
...
pair<const Sales_data, pf>::iterator it = bookstore.begin();

Exercise 11.20: rewrite the word counting program in exercise 11.1 (page 376) and use insert instead of subscript operation. Which program do you think is easier to write and read? Explain why.

[Topic setting ideas]

Be familiar with the different insertion methods of associated containers.

[answer]

The method of using insert operation is to construct a pair (word, 1), insert it into the container with insert, and return a pair. If the word already exists, the second member of the pair returned is false, indicating that the insertion fails. The programmer also needs to increment the counter of the existing word by returning the first member (iterator) of the pair. It is entirely the responsibility of the programmer to judge whether the word already exists and carry out the corresponding operation.

The way to use subscript operation is: obtain the element value with the word as the subscript. If the word already exists, extract the value of the existing element; Otherwise, the subscript operation inserts pair (word, 0) into the container and extracts the value of the new element. The relevant processing of whether the word already exists is completely handled by subscript operation. Programmers don't have to care. They can directly access the extracted value.

Obviously, for word counting, subscript operation is more concise and easy to read.

#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <algorithm>

using namespace std;

int main(int argc, const char * argv[])
{
    ifstream in(argv[1]);
    if(!in)
    {
        cout << "Failed to open input file!" << endl;
        exit(1);
    }

    map<string, size_t> word_count;     //string to count mapping
    string word;
    while(in >> word)
    {
//        auto ret = word_count.insert({word, 1});// Insert word 1 times
//        if(!ret.second) / / insert failed. The word already exists
//            ++ret.first->second;                // Increase the number of occurrences of existing words by 1
        ++word_count[word];                     //subscripts 
    }

    for(const auto &w: word_count)              //For each element in the map
    {
        //Print results
        cout << w.first << "There it is " << w.second << " second" << endl;
    }

    return 0;
}

data10_ The contents of 20.txt file are:

the quick red fox jumps over the the slow over red turtle

Set the command line parameters, and the running results are as follows:

Exercise 11.21: assume word_count is a string to size_t's map and word are a string, explaining the function of the following loop:

while(cin >> word)
        ++word_count.insert({word, 0}).first->second;

[Topic setting ideas]

Continue to familiarize yourself with the insert operation of the associated container.

[answer]

The loop continues to read words (strings) from standard input until the end of the file or an error is encountered.

Each time a word is read in, pair {word, 0} is constructed and inserted into word through insert operation_ Count. Insert returns a pair whose first member is an iterator. If word (keyword) already exists in container, it points to existing element; Otherwise, it points to the newly inserted element.

Therefore,. first will get this iterator and point to the element corresponding to word. Continue to use - > second to obtain the reference of the value of the element, that is, the count of words. If the word is new, its value is 0; if it already exists, its value is the number of previous occurrences. Increment it, that is, increase the number of occurrences by 1.

In this way, the previous question can be a little simpler.

Exercise 11.22: given a map < string, vector < int > >, insert the insert version of an element into this container, and write out its parameter type and return type.

[Topic setting ideas]

Continue to familiarize yourself with the insert operation of the associated container.

[answer]

The parameter type is a pair, the type of the first member is the keyword type string of the map, and the type of the second member is the value type vector < int >:

        pair<string, vector<int>>

The return type is also a pair. The type of the first member is the iterator of the map, and the type of the second member is Boolean:

        pair<map<string, vector<int>>::iterator, bool>

The map in exercise 11.23:11.2.1 (page 378) takes the child's last name as the keyword, saves the vector of their first name, and rewrites the map with multimap.

[Topic setting ideas]

This exercise allows you to repeat the insert operation of the keyword's associated container.

[answer]

Since repeated keywords are allowed, it is no longer necessary for vector to save the list of children's names in the same family. You can directly save each child's (last name, first name) pair. The container type becomes Multimap < string, string >. Add is no longer required_ Add family, keep only add_ Children can be added directly with the insert operation.

#include <iostream>
#include <map>
#include <string>
#include <algorithm>

using namespace std;

void add_child(multimap<string, string> &families, const string &family, const string &child)
{
    families.insert({family, child});
}

int main()
{
    multimap<string, string> families;
    add_child(families, "Zhang", "strong");
    add_child(families, "Zhang", "Just.");
    add_child(families, "king", "five");

    for(auto f: families)
    {
        cout << f.first << "Children at home:" << f.second << endl;
    }

    return 0;
}

Operation results:

Exercise 11.24: what does the following procedure do?

 map<int, int> m;
 m[0] = 1;

[Topic setting ideas]

Continue to be familiar with the subscript operation of map.

[answer]

If the keyword 0 already exists in M, the subscript operation extracts its value, and the assignment statement sets the value to 1. Otherwise, the subscript operation will create a pair (0, 0), that is, the keyword is 0 and the value is 0 (value initialization), insert it into m, extract its value, and set the value to 1 in the assignment statement.

Exercise 11.25: compare the following procedure with the previous one

vector<int> v;
v[0] = 1;

[Topic setting ideas]

Understand the differences in subscript operations between sequential containers and associated containers.

[answer]

For m, "0" means "keyword 0". For v, "0" means "position 0". If there is at least one element in v, that is, there is an element of "position 0", the subscript operation extracts the element (lvalue) of this position, and the assignment operation sets it to 1. The element of map is of pair type, and the subscript extracts not the element, but the second member of the element, that is, the value of the element. If v is still empty, the subscript extracts an illegal lvalue (the subscript operation does not check the range), and assigning a value to it may lead to serious consequences such as system crash.

Exercise 11.26: what types can be used to subscript a map? What is the type returned by the subscript operator? Please give a specific example -- that is, define a map, and then write out a type that can be used for subscript operation on the map and the type that will be returned by the subscript operator.

[Topic setting ideas]

Understand the various types of subscript operations involved in map.

[answer]

When subscribing to a map, its key should be used_ Type, that is, the type of keyword.

The type returned by the subscript operation is mapped_type, that is, the type of the value associated with the keyword.

Examples are as follows: map type: Map < string, int >

Type used for subscript operation: string

Type returned by subscript operation: int

Exercise 11.27: what problem would you use count to solve? When will you choose find?

[Topic setting ideas]

Understand the differences between different algorithms on the association container.

[answer]

find finds the location of the keyword in the container, and count counts the number of occurrences of the keyword. Therefore, when we want to know how many elements in the container (where duplicate keywords are allowed) have the same keyword as the given keyword, use count.

When we only care about whether the keyword is in the container, find is enough. In particular, for associated containers that do not allow duplicate keywords, the effects of find and count are no different. Use find. Or, when we need to get the elements with a given keyword (not just count the number), we also need to use find.

There is an important difference between find and subscript operation. When a given keyword is not in the container, the subscript operation will insert an element with that keyword. Therefore, when we want to check whether a given keyword exists, we should use find instead of subscript.

Exercise 11.28: for a map of a vector from string to int, define and initialize a variable to save the result returned by calling find on it.

[Topic setting ideas]

Understand find on map.

[answer]

find returns an iterator pointing to the element with the given keyword (or the trailing iterator if it does not exist), so its return type is the iterator of the container.

//map type
map<string, vector<int>> m;
//A variable that holds the result returned by find
map<string, vector<int>>::iterator iter;

Exercise 11.29: if the given keyword is not in the container, upper_bound,lower_bound and equal_ What will range return?

[Topic setting ideas]

Familiar with iterator based keyword search methods suitable for multimap and multiset.

[answer]

lower_bound returns the first element with the given keyword, upper_bound returns the position after the last element with the given keyword. That is, the two iterators form a scope that contains all elements with a given keyword. If a given keyword is not in the container, the two operations should obviously form an empty range, and they return equivalent iterators to indicate the correct insertion position of the keyword - without affecting the sorting of the keyword. If the given keyword is larger than all the keywords in the container, this position is the end position of the container.

equal_range returns a pair whose first member is equivalent to lower_ The iterator returned by bound. The second member is equivalent to upper_ Iterator returned by bound. Therefore, if the given keyword is not in the container, both first and second point to the correct insertion position of the keyword, and the two iterators form an empty range.

Exercise 11.30: for the output expression in the last program in this section, explain the meaning of the operand pos.first - > second.

[Topic setting ideas]

Familiar with equal_ Use of range.

[answer]

equal_range returns a pair whose first member is the same as lower_ The return result of bound is the same, that is, it points to the first element in the container with the given keyword. Therefore, dereferencing it will get a value_type object, that is, a pair, whose first is the keyword of the element, that is, the given keyword, and second is the value associated with the keyword. In this example, the keyword is the author and the associated value is the title of the work. Therefore, pos.first - > second is the title of the first book of a given author.

Exercise 11.31: write a program to define a multimap of an author and his works. Use find to find an element in the multimap and erase it. Make sure your program works when the element is not in the map.

[Topic setting ideas]

Practice inserting, finding, and deleting multimap s.

[answer]

To insert data into a multimap, you need to use the insert operation.

There are several ways to find elements with a given keyword in multimap: use find to find only the first element with a given keyword. To find all elements with a given keyword, you need to write a loop; lower_bound and upper_bound is used together to find the range of elements with a given keyword; equal_range is the simplest. You can get the range of elements to find at one time.

Pass the found scope to erase to delete all works of the specified author.

To solve the case where the element is not in the multimap, first check equal_ If the two iterators returned by range are equal (empty range), they do nothing. When the range is not empty, the iterator is passed to erase to delete all elements.

#include <iostream>
#include <string>
#include <map>
#include <algorithm>

using namespace std;

void remove_author(multimap<string, string> &books, const string &author)
{
    auto pos = books.equal_range(author);   //Find a given author range
    if(pos.first == pos.second)             //Empty range, no author
        cout << "No," << author << "This author" << endl;
    else
        books.erase(pos.first, pos.second); //Delete all works of the author
}

void print_books(multimap<string, string>& books)
{
    cout << "The current bibliography includes:" << endl;
    for(auto &book: books)                  //Traverse all books and print them
        cout << book.first << ", <" << book.second << ">" << endl;
    cout << endl;
}

int main()
{
    multimap<string, string> books;
    books.insert({"Barth, John", "Sot-Weed Factor"});
    books.insert({"Jin Yong", "Legend of Shooting Heroes"});
    books.insert({"Barth, John", "Lost in the Funhouse"});
    books.insert({"Jin Yong", "Tianlong Babu"});

    print_books(books);

    remove_author(books, "Zhang San");

    remove_author(books, "Barth, John");

    print_books(books);

    return 0;
}

Operation results:

  Exercise 11.32: write a program using the multimap defined in the previous question to print the list of authors and their works in dictionary order.

[Topic setting ideas]

This topic requires understanding the order of keywords in the multimap data structure and using it to realize the orderly output of keywords.

[answer] the data structure of multimap is a red black tree, which maintains the default order of element keywords. For example, for string keywords (authors), the red black tree maintains their dictionary order. When we traverse a multimap (such as [begin(), end()), or more simply use the range for), we access the elements in the dictionary order of the keywords.

Therefore, the print of the previous question_ Books actually has the ability to print author lists and their works in dictionary order.

However, it is more complicated when we do not require the default order of keywords (operator < defined order). Because the sort algorithm requires that the given two iterators are random iterators, the iterators of the associated container do not meet this requirement, so the sort algorithm cannot be used directly. In fact, it is not difficult to understand that the fundamental feature of the associated container is to maintain the default order of keywords, so as to realize the insertion, deletion and search by keywords. It is impossible to make its internal elements present another order through sort. It is only possible to arrange the order (position) of elements at will if they do not care about the order container of element values. When defining a multimap, we can use the order of keywords defined by the comparison operation defined by ourselves instead of the order defined by < but this only makes the multimap maintain keywords in another order, and it is still impossible to change the order of keywords in the process of using the multimap. Therefore, we can only copy the elements in the multimap to a sequential container (such as vector), and execute the sort algorithm on the sequential container to obtain other sequences of keywords.

Exercise 11.33: implement your own version of the word converter.

[Topic setting ideas]

Comprehensive exercise of associating containers.

[answer]

    {
        if(value.size() > 1)//Check whether there are conversion rules
            trans_map[key] = value.substr(1);//Skip leading spaces
        else
            throw runtime_error("no rule for " + key);
    }

    return trans_map;
}

//Generate conversion file
const string& transform(const string &s, const map<string, string> &m)
{
    //Actual conversion work: this part is the core of the program
    //map<string, string>::const_iterator map_it = m.find(s);
    auto map_it = m.find(s);
    //If the word is in the conversion map
    if(map_it != m.end())
        return map_it->second;//Use replacement phrase
    else
        return s;//Otherwise, the original string is returned
}
//Word converter
void word_transform(ifstream &map_file, ifstream &input)
{
    //map<string, string> trans_map = buildMap(map_file);
    auto trans_map = buildMap(map_file);//Save conversion rule
    cout << "here is our transformation map:" <<endl;

    for(map<string, string>::const_iterator entry = trans_map.begin(); entry != trans_map.end(); ++entry)
        cout << "key: " << entry->first << "\tvalue: " << entry->second << endl;

    cout << "\n\n";
    string text;//Save each line in the input
    while(getline(input, text))//Read one line of input
    {
        istringstream stream(text);//Read each word
        string word;
        bool firstword = true;
        while(stream >> word)
        {
            if(firstword)
                firstword = false;
            else
                cout << " ";//Print a space between words
            //transform returns its first argument or its converted form
            cout << transform(word, trans_map);//Printout
        }
        cout << endl;//Complete the conversion of one line
    }
}


int main(int argc, const char * argv[])
{
    if(argc != 3)
        throw runtime_error("wrong number of arguments");

    ifstream map_file(argv[1]);
    if(!map_file)
        throw runtime_error("no transformation file");

    ifstream input(argv[2]);
    if(!input)
        throw runtime_error("no input file");
    word_transform(map_file, input);
    return 0;
}

data11_ 33_ The contents of map.txt are as follows:

brb be right back

k okay?

y why

r are

u you

pic picture

the thanks!

l8r later

data11_ 33_ The contents of input.txt are as follows:

where r u

y don't u send me a pic

k the l8r

Set command line parameters:

  Operation results:

  Exercise 11.34: what happens if you replace find in the transform function with a subscript operator?

[question setting idea] continue to understand the difference between find and subscript operation.

[answer]

As mentioned earlier, find only finds whether the given keyword appears in the container. If the given keyword does not exist in the container, it returns the trailing iterator. When the keyword exists, the behavior of the subscript operator is similar to find, but when the keyword does not exist, it constructs a pair (value initialization) and inserts it into the container. For word converters, this inserts non-existent content into the output text, which is obviously not what we expect.

Exercise 11.35: in buildMap, what effect will it have if you rewrite it as follows?

trans_map[key] = value.substr(1);
Change to trans_map.insert({key, value.substr(1)})

[Topic setting ideas]

Continue to understand the difference between insert and subscript operations.

[answer]

When there is no given keyword in the map, the effect of insert operation is similar to that of subscript operation + assignment operation. Both add the pair of keyword and value to the map.

However, when a given keyword is already in the map, that is, the new conversion rule and an existing rule want to convert the same word, their behavior is different. The subscript operation will obtain the value of the element with the keyword (that is, the existing rule) and assign the newly read value to it, that is, overwrite the existing rule in the container with the newly read rule. However, if the keyword already exists in the insert operation, the contents of the container will not be changed, but a value will be returned indicating that the insertion failed. Therefore, when multiple rules in the rule file convert the same word, the version with subscript + assignment will eventually use the last rule for text conversion, while the insert version will use the first rule for text conversion.

Exercise 11.36: our program does not check the validity of the input file. In particular, it assumes that the rules in the transformation rule file are meaningful. What happens if a line in the file contains a keyword, a space, and then ends? Predict the behavior of the program, verify it, and compare it with your program.

[Topic setting ideas]

Practice string processing skills.

[answer]

This problem is wrong. The program in the book has dealt with this situation. In the buildMap function, after reading the word to be converted and the converted content in the loop, it will check whether the converted content exists (value. Size() > 1). If it does not exist, an exception will be thrown. Of course, the program only handles this kind of error. You can think about other errors and write a program to deal with them.

Posted on Thu, 07 Oct 2021 04:13:12 -0400 by Bou