C + + premier plus (Sixth Edition) Chapter 16 string class and standard template library programming practice answers

Posted by Toshiba23 on Wed, 12 Jan 2022 06:52:56 +0100

1. Palindromes refer to strings that are the same in both forward and reverse reading. For example, "tot" and "Otto" are simple palindromes. Write a program to input a string and pass the string reference to a bool function. If the string is a palindrome, the function returns true; otherwise, it returns false. Don't worry about complex problems such as case, spaces, and punctuation at this time. That is, this simple version will reject "Otto" and "Madam, I'm Adam". Please see the list of string methods in Appendix F to simplify this task.

The difficulty of this problem is to return the palindrome of the string before judging whether it is a palindrome. There was a problem in writing the function to return palindromes. The last character should be size()-1 instead of size().
The procedure is as follows:

// pe1.cpp -- test palindrome
#include <iostream>
#include <string>

std::string palindrome(const std::string & s);
bool is_palindrome(const std::string & s);
int main()
{
    using std::cout;
    using std::string;
    using std::cin;
    string input;
    cout << "Enter a word(quit to quit): ";
    while (cin >> input && input != "quit")
    {
        if (is_palindrome(input))
            cout << input << " is palindrome\n";
        else
            cout << input << " is not palindrome\n";
        cout << "Enter a word(quit to quit): ";
    }
    cout << "Done\n";
    return 0;
}

std::string palindrome(const std::string & s)       // get the palindrome of string s
{
    std::string result;
    int size = s.size();
    result = s;
    char temp;
    for (int i = 0, j = size-1; i < j; i++, j--)    // j should be size - 1
    {
        temp = s[i];
        result[i] = result[j];
        result[j] = temp;
    }
    return result;
}

bool is_palindrome(const std::string & s)
{
    return palindrome(s) == s;
}

The operation results are as follows:

2. The same problem as given in programming exercise 1, but consider complex problems such as case, space and punctuation. That is, "Madam, I'm Adam" will be tested as palindromes. For example, a test function might abbreviate a string to "madamimadam" and then test whether the reverse is the same. Don't forget the useful cctype library, from which you may find several useful STL functions, although you don't have to use them.

This topic uses the code in exercise 1 and adds a preprocessing function again. This function creates the notalpha() function through the isalpha() function to find non alphabetic characters and use remove_if(), delete the non alphabetic characters. After deletion, you need to erase the tail interval. After deletion, you need to convert lowercase letters. You can use your own function to realize it by calling your own tolower() function, which returns tower(). The code is as follows:

// pe2.cpp -- test palindrome
#include <iostream>
#include <cctype>
#include <string>
#include <algorithm>
bool notalpha(char ch) { return !isalpha(ch); }     // is not alpha
char toLower(char ch) { return tolower(ch); }       // ch to lower
std::string ToLower(const std::string & s);                      // string to lower
std::string predeal(const std::string & s);                      // delete not alpha and ToLower
std::string palindrome(const std::string & s);
bool is_palindrome(const std::string & s);
int main()
{
    using std::cout;
    using std::string;
    using std::cin;
    string input;
    cout << "Enter a line of string (quit to quit): ";
    while (getline(cin, input) && input != "quit")
    {
        string deal_s = predeal(input);
        if (is_palindrome(deal_s))
            cout << input << " is palindrome\n";
        else
            cout << input << " is not palindrome\n";
        cout << "Enter a line of string (quit to quit): ";
    }
    cout << "Done\n";
    return 0;
}

std::string ToLower(const std::string & s)
{
    std::string temp;
    for (int i = 0; i < s.size(); i++)
        temp[i] = toLower(s[i]);
    return temp;
}
std::string predeal(const std::string & s)
{
    std::string deal_result;
    deal_result = s;
    auto end_ir = remove_if(deal_result.begin(), deal_result.end(),notalpha);
    deal_result.erase(end_ir, deal_result.end());
    return ToLower(deal_result);
}
std::string palindrome(const std::string & s)       // get the palindrome of string s
{
    std::string result;
    int size = s.size();
    result = s;
    char temp;
    for (int i = 0, j = size-1; i < j; i++, j--)    // j should be size - 1
    {
        temp = s[i];
        result[i] = result[j];
        result[j] = temp;
    }
    return result;
}

bool is_palindrome(const std::string & s)
{
    return palindrome(s) == s;
}

The operation results are as follows:

###3. Modify program listing 16.3 to read words from the file. One option is to use a vector < string > object instead of a string array. This allows you to use push_back() copies the words in the data file into the vector < string > object, and uses size() to determine the length of the word list. Since the program should read one word at a time from the file, the operator > > should be used instead of getline(). The words contained in the file should be separated by spaces, tabs, or line breaks. The test of this question is to read words from a file. Here, choose to save the read words in the vector < string > object, and you can call the push of the object_ The back () method reads the word from the file. First declare an ifstream object inFile, associate the file with the object through the open method, and read the word through inFile > > word. You can use the while loop. The operation in the loop is to insert the word into the tail of the vector, and finally close the file to complete the reading. After reading, you can modify the statement generated by target. The program is as follows:
// pe3.cpp -- test hangman words form file
#include <iostream>
#include <fstream>
#include <cctype>
#include <string>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <ctime>

int main()
{
    using std::cout;
    using std::string;
    using std::cin;
    using std::vector;
    using std::ifstream;
    vector<string> wordlist;
    string word;            // record word from file
// input words from files
    ifstream inFlie;
    inFlie.open("wordlist.txt");
    if (!inFlie.is_open())
    {
        cout << "Can't open the file. Bye.\n";
        exit(EXIT_FAILURE);
    }
    while (inFlie >> word)
        wordlist.push_back(word);
    inFlie.close();
// hangman game
    char play;
    cout << "Will you play the game? <y/n>";
    cin >> play;
    play = tolower(play);
    while (play == 'y')
    {
        srand(time(0));
        string target = wordlist[rand() % wordlist.size()];
        int length = target.size();
        string attempt(length, '-');
        string badchars;
        int guesses = target.size();
        cout << "Guess my secret word. It has " << length 
             << " letters, and your guess\n"
             << "one letter at a time. You get "<< guesses
             << " wrong guesses.\n";
        while (guesses > 0 && attempt != target)
        {
            char letter;
            cout << "Guess a letter: ";
            cin >> letter;
            if (attempt.find(letter) != string::npos || 
                badchars.find(letter) != string::npos)
            {
                cout << "You have guessed the letter. Try again.\n";
                continue;
            }
            int pos = target.find(letter);
            if (pos == string::npos)
            {
                cout << "Oh, bad guess!\n";
                badchars += letter;
                guesses--;
            }
            else
            {
                cout << "Good guess!\n";
                while (pos != string::npos)
                {
                    attempt[pos] = letter;
                    pos = target.find(letter,pos + 1);
                }
            }
            cout << "Your word: " << attempt << std::endl;
            if (attempt != target)
            {
                if (badchars.size() > 0)
                    cout << "Bad choices: " << badchars << std::endl;
                cout  << guesses << " bad guesses left\n";
            }
        }

        if (guesses > 0)
            cout << "Congratlations! You guess the word: " << target << std::endl;
        else
            cout << "Sorry, the word is " << target << std::endl;
        cout << "Will you play another? <y/n>";
        cin >> play;
    }
    cout << "Done\n";
    return 0;
}

wordlist.txt file is as follows:
apiary beetle cereal
danger ensign florid garage health insult
jackal keeper losner manage nonce onset
plaid quilt remote stolid train useful
valid whence xenon yearn zippy
Note wordlist Txt should be in the same directory as the C + + file. If not, you need to enter the absolute path of the file. The operation results are as follows:


4. Write a function with old style interface, and its prototype is as follows:

int reduce(long ar[], int n);
The argument should be the array name and the number of elements in the array. This function sorts the array, removes duplicate values, and returns the number of elements in the reduced array. Write this function using the STL function (if you decide to use the generic unqiue() function, note that it will return the end of the result interval). Use an applet to test the function.
There are two implementation methods for this problem. One is to use the set container. You only need to insert the elements of ar into the set container, and then copy the contents of the set container into the ar array. The new length of the array can be set by the set container size() method, the procedure is as follows:

// pe4.cpp -- definition of int reduce(long ar[], int n) and use STL
#include <iostream>
#include <set>
#include <cstdlib>
#include <ctime>

int reduce(long ar[], int n);

int main()
{
    using std::cout;
    using std::endl;
    srand(time(0));
    const int LIM = 20;
    long testar[LIM];
    for (int i = 0; i < LIM; i++)
        testar[i] = rand() % 10;
    cout << "Before using reduce() function, the test array:\n";
    for (int i = 0; i < LIM; i++)
    {
        cout << testar[i] << " ";
        if (i % 10 == 9)
            cout << "\n";
    }
    if (LIM % 10 != 0)
        cout << endl;
    int len = reduce(testar, LIM);
    cout << "After using reduce() function, the test array:\n";
    for (int i = 0; i < len; i++)
    {
        cout << testar[i] << " ";
        if (i % 10 == 9)
            cout << "\n";
    }
    if (len % 10 != 0)
        cout << endl;
    cout << "Done\n";
    return 0;

}

int reduce(long ar[], int n)
{
    std::set<long> temp;
    // std::vector<long> temp(n);
    for (int i = 0; i < n; i++)
        temp.insert(ar[i]);
    int len = temp.size();
    int i;
    copy(temp.begin(), temp.end(), ar);
    return len;
}

Another method is to sort the array with sort(). After sorting, use unique to delete the same element, and then use the returned super tail iterator to subtract the address of the head end of AR, which is the new length of ar. the procedure is as follows:

// version use sort and unique
int reduce(long ar[], int n)
{
    std::sort(ar, ar + n);
    auto air = std::unique(ar, ar + n);
    return (air - ar) ;
}

The operation results are as follows:

5. The problem is the same as that in programming exercise 4, but a template function should be written:

template<class T>
int reduce(long ar[], int n);
Test the function in an applet that uses a long instance and a string instance.

This problem is very simple. There are few places to modify. For the sort() and unique() versions, you only need to modify the declaration of function parameters, while the se version modifies the set Declaration on this basis. The procedure is as follows:

// pe5.cpp -- template definition of int reduce(long ar[], int n) and use STL

// pe4.cpp -- definition of int reduce(long ar[], int n) and use STL
#include <iostream>
#include <set>
#include <algorithm>
#include <cstdlib>
#include <ctime>

template <class T>
int reduce(T ar[], int n);

int main()
{
    using std::cout;
    using std::endl;
    srand(time(0));
// test long numbers
    const int LIM = 20;
    long testar[LIM];
    for (int i = 0; i < LIM; i++)
        testar[i] = rand() % 10;
    cout << "Before using reduce() function, the test array:\n";
    for (int i = 0; i < LIM; i++)
    {
        cout << testar[i] << " ";
        if (i % 10 == 9)
            cout << "\n";
    }
    if (LIM % 10 != 0)
        cout << endl;
    int len = reduce<long>(testar, LIM);
    cout << "After using reduce() function, the test array:\n";
    for (int i = 0; i < len; i++)
    {
        cout << testar[i] << " ";
        if (i % 10 == 9)
            cout << "\n";
    }
    if (len % 10 != 0)
        cout << endl;
// test string
    std::string test_sar[LIM] = {"Union", "for", "cat", "dog", "for", "why", "how", "what", "want", "cat",
        "white", "can", "air", "dog", "for", "why", "how", "what", "want", "cat"};
    cout << "Before using reduce() function, the test array:\n";
    for (int i = 0; i < LIM; i++)
    {
        cout << test_sar[i] << " ";
        if (i % 10 == 9)
            cout << "\n";
    }
    if (LIM % 10 != 0)
        cout << endl;
    len = reduce<std::string>(test_sar, LIM);
    cout << "After using reduce() function, the test array:\n";
    for (int i = 0; i < len; i++)
    {
        cout << test_sar[i] << " ";
        if (i % 10 == 9)
            cout << "\n";
    }
    if (len % 10 != 0)
        cout << endl;
    cout << "Done\n";
    return 0;

}
// version use set
template <class T>
int reduce(T ar[], int n)
{
    std::set<T> temp;
    // std::vector<long> temp(n);
    for (int i = 0; i < n; i++)
        temp.insert(ar[i]);
    int len = temp.size();
    int i;
    copy(temp.begin(), temp.end(), ar);
    return len;
}

// // version use sort and unique
// template <class T>
// int reduce(T ar[], int n)
// {
//     std::sort(ar, ar + n);
//     auto air = std::unique(ar, ar + n);
//     return (air - ar) ;
// }

The operation results are as follows:

6. Rewrite the example shown in listing 12.12 using the STL queue template class instead of the Queue class in Chapter 12.

This problem is not difficult. First add the queue header file, then add the definition of customer class, method implementation, modify the generated queue line without limiting the length, modify the code to if(line.size() == qs) when judging whether the queue is full, use the method push when entering the queue, use the method pop when leaving the queue, and use line before leaving the right queue The front () method reads the class at the head of the queue. The procedure is as follows:

// pe6.cpp use queue to realize bank
#include <iostream>
#include <cstdlib>      // for rand() and srand()
#include <ctime>        // for time()
#include <queue>
const int MIN_PER_HR = 60;

// Custormer items
class Customer
{
private:
    long arrive;                // arrive time for customer
    int processtime;            // processing time for customer
public:
    Customer() { arrive = processtime = 0; }

    void set(long when);
    long When() const { return arrive; }
    int Ptime() const { return processtime; }
};
typedef Customer Item;
// time set to a random value in the range 1 - 3
void Customer::set(long when)
{
    processtime = std::rand() % 3 + 1;
    arrive = when;
}

bool newcustomer(double x); // is there a new customer

int main()
{
    using std::cin;
    using std::cout;
    using std::endl;
    using std::ios_base;
    using std::queue;
// setting things up
    std::srand(std::time(0));   // random intializing of rand

    cout << "Case Study: Bank of Heather Automatic Teller\n";
    cout << "Enter the maximum size of queue: ";
    int qs;
    cin >> qs;
    queue<Item> line;            // line queue holds up to qs people

    cout << "Enter the number of simulation hours: ";
    int hours;
    cin >> hours;
    // simulation will run 1 cycle per minute
    long cyclelimit = MIN_PER_HR * hours;  // # of cycles

    cout << "Enter the average number of customers per hour: ";
    double perhour;
    cin >> perhour;
    double min_per_cust;
    min_per_cust = MIN_PER_HR / perhour;

    Item temp;                 // new customer data
    long turnaways = 0;        // turn away by full queue
    long customers = 0;        // joined the queue
    long served = 0;           // served during the simulation
    long sum_line = 0;         // cmulative line length
    long wait_time = 0;        // time untile autoteller is free
    long line_wait = 0;        // cumulative time in line
// running the  simulation
    for (int cycle = 0; cycle < cyclelimit; cycle++)
    {
        if(newcustomer(min_per_cust))   // have newcomer
        {
            if(line.size() == qs)
                turnaways++;
            else
            {
                customers++;
                temp.set(cycle);        // cycle = time of arrival
                line.push(temp);
                // line.enqueue(temp);     // add newcomer to line
            }
        }
        if(wait_time <= 0 && !line.empty())
        {
            temp = line.front();
            line.pop();         // attend next customer
            wait_time = temp.Ptime();   // for wait_time minuetes
            line_wait += cycle - temp.When();
            served++;
        }
        if(wait_time > 0)
            wait_time--;
        sum_line += line.size();
    }
// reporting results
    if(customers > 0)
    {
        cout << "customers accepted: " << customers << endl;
        cout << "  customers served: " << served << endl;
        cout << "         turnaways: " << turnaways << endl;
        cout << "average queue size: ";
        cout.precision(2);
        cout.setf(ios_base::fixed, ios_base::floatfield);
        cout << (double) sum_line / cyclelimit << endl;
        cout << " avergae wait time: "
             << (double) line_wait / served << "minutes\n";
    }
    else
        cout << "No customerr!\n";
    cout << "Done!\n";

    return 0;
}

// x = average time in minutes, between customers
// return value is true if customer shows up this minute
bool newcustomer(double x)
{
    return (std::rand() * x / RAND_MAX < 1);
}

The operation results are as follows:

7. Lottery card is a common game. On the card are numbered dots, some of which are randomly selected. Write a lotto() function that takes two arguments. The first parameter is the number of dots on the lottery card, and the second parameter is the number of dots randomly selected. This function returns a vector < int > object containing randomly selected numbers (in the order after arrangement). For example, you can use this function as follows:

vector<int>winners;
winners = Lotto(51,6);
In this way, a vector is assigned to winner, which contains 6 randomly selected numbers from 1 to 51. Note that rand() alone cannot do this because it generates duplicate values. Tip: let the function create a vector containing all possible values, using random_shuffle(), and then get the value by the first value of the scrambled vector.
This question adopts the idea of the prompt in the question, and uses the first value after random disturbance to obtain the value. During the test, it is found that the value may also be repeated. Therefore, a while loop is added to judge whether the first value is in the result. If so, randomly generate a sequence again until the first value is not in the result container, and take the first value; Another method is to generate a random sequence in which 6 values are randomly taken. If they are repeated, they are not added until the position is not repeated. The first method is adopted here, and the procedure is as follows:

// pe7.cpp -- simulation of lottery card
#include <iostream>
#include <vector>
#include <algorithm>

using std::vector;

vector<int> Lotto(int numbers, int num_choices);
void show(int x) { std::cout << x << ' ';}
int main()
{
    using std::cout;
    using std::cin;
    using std::endl;
    int numebrs, num_choices;
    cout << "Enter the numbers of point and the numebr of chooses <q to quit>: ";
    while (cin >> numebrs >> num_choices)
    {
        auto winner = Lotto(numebrs,num_choices);
        cout << "The winner's numbers is ";
        std::for_each(winner.begin(), winner.end(), show);
        cout << endl;
        cout << "Enter next two numbers <q to quit>: ";
    }
    return 0;
}

vector<int> Lotto(int numbers, int num_choices)
{
    vector<int> temp;
    vector<int> result;
    for (int i = 1; i <= numbers; i++)
        temp.push_back(i);
    for (int i = 0; i < num_choices; i++)
    {
        std::random_shuffle(temp.begin(), temp.end());
    // make sure the value not repeat
        while (find(result.begin(), result.end(),temp[0]) != result.end())
            std::random_shuffle(temp.begin(), temp.end());
        result.push_back(temp[0]);
    }
    return result;
}

The operation results are as follows:

8. Mat and Pat want to invite their friends to the party. They need to write a program to complete the following tasks.

  • Ask Mat to enter a list of his friends' names. Names are stored in a container and then displayed in order.
  • Ask Pat to enter a list of her friends' names. The names are stored in another container and then displayed explicitly in the order in which they are arranged.
  • Create a third container, merge the two lists, delete the duplicate parts, and display the contents of this container.

This problem is not difficult. Use the set container to solve this problem. When writing a program, in set_ There is a problem with the use of the Union () function. The fifth iterator should be an output iterator, and pm_union.begin() is an input iterator, so an error is raised at compile time. Insert is added_ After the iterator iterator, the program is correct. The program is as follows:

// pe8.cpp -- use set and set_union
#include <iostream>
#include <set>
#include <string>
#include <algorithm>
#include <iterator>

void show(const std::string & s) { std::cout << s << "; "; }
int main()
{
    using std::cout;
    using std::cin;
    using std::endl;
    using std::set;
    using std::string;
    using std::for_each;
// mat
    set<string> mat;
    string name;
    cout << "Dear mat, please enter your friend's name <quit to quit>: ";
    while (getline(cin, name) && name != "quit")
    {
        mat.insert(name);
        cout << "enter next name <quit to quit>: ";
    }
    cout << "Mat's friend list:\n";
    for_each(mat.begin(), mat.end(), show);
    cout << endl;
// pat
    set<string> pat;
    cout << "Dear pat, please enter your friend's name <quit to quit>: ";
    while (getline(cin, name) && name != "quit")
    {
        pat.insert(name);
        cout << "enter next name <quit to quit>: ";
    }
    cout << "Pat's friend list:\n";
    for_each(pat.begin(), pat.end(), show);
    cout << endl;
// set_union
    set<string> pm_union;
    std::set_union(mat.begin(), mat.end(), pat.begin(), pat.end(), 
        std::insert_iterator< set<string> >(pm_union, pm_union.begin()));
    cout << "Pat and Mat friend list:\n";
    for_each(pm_union.begin(), pm_union.end(), show);
    cout << endl;
    cout << "Done\n";
    return 0;
}

The operation results are as follows:

9. Compared with arrays, it is easier to add and delete elements in the linked list, but the sorting speed is slower. This leads to a possibility: compared with sorting using the linked list algorithm, copying the linked list to the array, sorting the array, and then copying the sorted results to the linked list may be faster; But it may also take up more memory. Please use the following method to test the above hypothesis.

a. Create a large vector < int > object vi0 and use rand() to provide it with an initial value.
b. Create vector < int > object VI and list < int > object li, both of which have the same length as the initial value vi0.
c. Calculate the time required to sort vi using STL algorithm sort(), and then calculate the time required to sort vi using list method and sort().
d. Reset li to the contents of sorted v10, and calculate the time required to copy the contents of li to vi, sort vi, and copy the results to li.
To calculate the time required for these operations, use clock() in the ctime library. As demonstrated in listing 5.14, the start time can be obtained using the following statement:
clock_t start = clock();
After the operation, use the following statement to obtain the elapsed time:
clock_t end = clock();
cout << (double)(end - start)/CLOCKS_PER_SEC;
This test is not absolutely reliable, because the result depends on many factors, such as the amount of memory available, whether it supports multiprocessing, and the length of the array (list) (the efficiency of the array relative to the list will be more obvious as the number of elements to be sorted increases). In addition, if the compiler provides a default build method and a publish build method, use the publish build method. Given the speed of today's computers, it may be necessary to use as large an array as possible to obtain meaningful results. For example, you can try to include 100000, 1000000, and 10000000 elements.
This question is not difficult, but there are several places to pay attention to. First, when using copy, the third iterator should insert an iterator of type, that is, insert_ Time of type iterator. After completing b and c, li and VI should be erased before copying vi0 to li. The procedure is as follows:

// pe9.cpp -- compare the speed list.sort and copy list to vector, sort, and copy to list
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <iterator>

const int LIM = 10000000;         // numbers of elements

int main()
{
    using std::cout;
    using std::sort;
    using std::list;
    using std::vector;
    using std::copy;
    using std::endl;
    using std::insert_iterator;

    cout << "Number of elements: " << LIM << endl;
// generate elements of vector<int> vi0
    srand(time(0));             // generate random seeds
    vector<int> vi0;
    for (int i = 0; i < LIM; i++)
        vi0.push_back(rand() % LIM);
// copy vi0 to ci and li
    vector<int> vi;
    list<int> li;
    copy(vi0.begin(), vi0.end(), insert_iterator<vector<int>>(vi, vi.begin()));
    copy(vi0.begin(), vi0.end(), insert_iterator<list<int>>(li, li.begin()));
/**** calculate the time of sort(vi) and li.sort() ****/
// calculate the time of sort(vi.begin(), vi.end());
    clock_t start = clock();
    sort(vi.begin(), vi.end());
    clock_t end = clock();
    cout << "The time of sort(vi.begin(), vi.end()):\n";
    cout << (double)(end - start) / CLOCKS_PER_SEC;
    cout << endl;
// calculate the time of list.sort();
    start = clock();
    li.sort();
    end = clock();
    cout << "The time of li.sort():\n";
    cout << (double)(end - start) / CLOCKS_PER_SEC;
    cout << endl;

/**** calculate the time of copy() + sort(vi.begin(),vi.end()) + copy() ****/
// clear list and vi
    li.erase(li.begin(), li.end());
    vi.erase(vi.begin(), vi.end());
// calculate time
    copy(vi0.begin(), vi0.end(), insert_iterator<list<int>>(li, li.begin()));
    start = clock();
    copy(li.begin(), li.end(), insert_iterator<vector<int>>(vi, vi.begin()));
    sort(vi.begin(), vi.end());
    copy(vi.begin(), vi.end(), insert_iterator<list<int>>(li, li.begin()));
    end = clock();
    cout << "The time of combination:\n";
    cout << (double)(end - start) / CLOCKS_PER_SEC;
    cout << endl;

    return 0;

}

Set the number of elements to 100000, 1000000 and 10000000 respectively, and the operation results are as follows:



The last one doesn't use the debugging tool provided by vscode. I guess the tool may limit memory. The last result can't be calculated. You can calculate the result by running it on the command line.

10. Please modify program list 16.9(vect3.cpp) as follows.

a. Add the member price in the structure Review.
b. Instead of using vector < Review > to store input, use vector < shared_ptr<Review>>. Don't forget to use the return pointer of new to initialize shared_ptr.
c. At the end of the input phase, a cycle is used to let the user select one of the following methods to display books: display in original order, display in alphabetical order, display in ascending order of rating, display in descending order of rating, display in ascending order of price, display in descending order of price, and exit.
Here is a possible solution: after obtaining the input, create a shared_ptr vector and initialize it with the original array. Define an operator < () function that compares pointers to structures, and use it to sort the second vector so that the shared_ptr sorts by the title of the book in the object it points to. Repeat the above process to create shared sorted by rating and price_ PTR vector. Note that by using rbegin() and rend(), you can avoid creating shared in reverse order_ PTR vector.
This question is more complicated. I checked the shared_ The use of PTR smart pointer and the programming of sorting function. Because the names are relatively long, typedef can be used to simplify the coding. The procedure is as follows:

// pe10.cpp -- using STL functions and shared_ptr
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>
#include <memory>
#include <iterator>


struct Review{
    std::string title;
    int rating;
    double price;
};
// using name
    using std::cin;
    using std::cout;
    using std::vector;
    using std::for_each;
    using std::shared_ptr;
    using std::sort;
    using std::copy;
    using std::insert_iterator;
// simplify the name
    typedef shared_ptr<Review> SpR;
    typedef vector<SpR>  VSpR;
    typedef insert_iterator<VSpR> insert_ir_VSpR;

bool FillReview(Review & rr);                           // input a book
SpR make_Review(Review & rr);       // return a shared_ptr of a book
void ShowMenu();                                        // display the menu
void ShowReview(const SpR spr);    // show a book
// compare the book of title 
bool operator<(const SpR spr1, const SpR spr2);
// compare the book of rating 
bool compare_rating(const SpR spr1, const SpR spr2);
// compare the book of price
bool compare_price(const SpR spr1, const SpR spr2);
void ShowBooks(const VSpR & vspr);
int main()
{
// input the book to books_spr
    VSpR books_ptr;
    vector<Review> books;
    Review temp;
    while (FillReview(temp))
        books_ptr.push_back(make_Review(temp));
    
    VSpR temp_books_ptr;    // prototype a temp_books_ptr to restore result
// output menu
    ShowMenu();
// display books_list
    char choice;
    while (cin >> choice && choice != 'q')
    {
    // if input other char
        if(!strchr("abcdef",choice))
        {
            cout << "Please enter a a, b, c, d, e, f, q <q to quit>: ";
            continue;
        }
        switch (choice)
        {
            case 'a': cout << "Orignal order:\nRating\tBook\tprice\n";
                      for_each(books_ptr.begin(), books_ptr.end(), ShowReview);
                      break;
            case 'b': temp_books_ptr.erase(temp_books_ptr.begin(), 
                            temp_books_ptr.end());
                      copy(books_ptr.begin(), books_ptr.end(), 
                            insert_ir_VSpR(temp_books_ptr, temp_books_ptr.begin()));
                      cout << "Letter order:\nRating\tBook\tprice\n";
                      sort(temp_books_ptr.begin(), temp_books_ptr.end());
                      for_each(temp_books_ptr.begin(), temp_books_ptr.end(), ShowReview);
                      break;
            case 'c': temp_books_ptr.erase(temp_books_ptr.begin(), 
                            temp_books_ptr.end());
                      copy(books_ptr.begin(), books_ptr.end(), 
                            insert_ir_VSpR(temp_books_ptr, temp_books_ptr.begin()));
                      cout << "Rating ascending order:\nRating\tBook\tprice\n";
                      sort(temp_books_ptr.begin(), temp_books_ptr.end(),compare_rating);
                      for_each(temp_books_ptr.begin(), temp_books_ptr.end(), ShowReview);
                      break;
            case 'd': temp_books_ptr.erase(temp_books_ptr.begin(), 
                            temp_books_ptr.end());
                      copy(books_ptr.begin(), books_ptr.end(), 
                            insert_ir_VSpR(temp_books_ptr, temp_books_ptr.begin()));
                      cout << "Rating decending order:\nRating\tBook\tprice\n";
                      sort(temp_books_ptr.begin(), temp_books_ptr.end(),compare_rating);
                      for_each(temp_books_ptr.rbegin(), temp_books_ptr.rend(), ShowReview);
                      break;
            case 'e': temp_books_ptr.erase(temp_books_ptr.begin(), 
                            temp_books_ptr.end());
                      copy(books_ptr.begin(), books_ptr.end(), 
                            insert_ir_VSpR(temp_books_ptr, temp_books_ptr.begin()));
                      cout << "Price ascending order:\nRating\tBook\tprice\n";
                      sort(temp_books_ptr.begin(), temp_books_ptr.end(),compare_price);
                      for_each(temp_books_ptr.begin(), temp_books_ptr.end(), ShowReview);
                      break;
            case 'f': temp_books_ptr.erase(temp_books_ptr.begin(), 
                            temp_books_ptr.end());
                      copy(books_ptr.begin(), books_ptr.end(), 
                            insert_ir_VSpR(temp_books_ptr, temp_books_ptr.begin()));
                      cout << "Price decending order:\nRating\tBook\tprice\n";
                      sort(temp_books_ptr.begin(), temp_books_ptr.end(),compare_price);
                      for_each(temp_books_ptr.rbegin(), temp_books_ptr.rend(), ShowReview);
                      break;
        }
        ShowMenu();
    }
    cout << "Done";
    return 0;
}

bool FillReview(Review & rr)
{
    std::cout << "Enter the book title (quit to quit): ";
    std::getline(std::cin, rr.title);
    if (rr.title == "quit")
        return false;
    std::cout << "Enter book rating: ";
    std::cin >> rr.rating;
    std::cout << "Enter book price: ";
    std::cin >> rr.price;
    while (std::cin.get() != '\n')
        continue;
    return true;
}

SpR make_Review(Review & rr)
{
    return SpR(new Review(rr));
}
void ShowMenu()
{
    using std::cout;
    using std::endl;
    cout << "Choice the display order <q to quit>:\n";
    cout << "a: orignal order       b: letter order\n";
    cout << "c: rating ascending    d: rating decending\n";
    cout << "e: price ascendding    f: price decending\n";
    cout << "q: quit\n";
}

void ShowReview(const SpR spr)
{
    std::cout << spr->rating << "\t" << spr->title << "\t$" << spr->price << std::endl;
}

bool operator<(const SpR spr1, const SpR spr2)
{
    if (spr1->title < spr2->title)
        return true;
    else if (spr1->title == spr2->title && spr1->rating < spr2->rating)
        return true;
    else if (spr1->title == spr2->title && spr1->rating == spr2->rating
        && spr1->price < spr2->price)
        return true;
    else
        return false;
}

bool compare_rating(const SpR spr1, const SpR spr2)
{
    if (spr1->rating < spr2->rating)
        return true;
    else if (spr1->rating == spr2->rating && spr1->title < spr2->title)
        return true;
    else if (spr1->title == spr2->title && spr1->rating == spr2->rating
        && spr1->price < spr2->price)
        return true;
    else
        return false;
}

bool compare_price(const SpR spr1, const SpR spr2)
{
    if (spr1->price < spr2->price)
        return true;
    else if (spr1->price == spr2->price && spr1->title < spr2->title)
        return true;
    else if (spr1->title == spr2->title && spr1->price == spr2->price
        && spr1->rating < spr2->rating)
        return true;
    else
        return false;
}

The operation results are as follows:

Topics: C++