Starting from:

$35

COMP5421- Assignment 5 Solved

1              Purpose
Familiar with standard sequence containers,12 we are now ready to also become familiar with std::multimap<>, one of the standard associative3 containers (sets and maps).4
The primary purpose is to practice using a few of the Standard Template Library (STL) algorithms, iterators, and containers, enough to get a feel for how to connect algorithms to containers with the help of iterators.
2              Setting the Stage For Tasks 1-5
To quickly get you to practice few standard algorithms on associative containers, this section provides some “boilerplate” code that you are already familiar with.

2.1            Input: Dog Records in a CSV File
Tasks 1-4 in this section each use a comma-separated values (CSV) input file named dogDB.csv whose contents are shown below. Each line in the file records four comma-separated strings of characters representing the name, breed, age, and gender of a dog, in that order.

Nacho, Bracco Italiano, 4, male

Toby, Chihuahua, 2, Male

Abby, Bull Terrier, 8, Female

Nacho, Coton de Tulear, 3, male

Coco, German Shepherd Dog, 13, Female

Abby, Flat-Coated Retriever, 1, female

Raven, Bull Terrier, 12, Male

Piper, Stabyhoun, 9, male

1such as std::array<>, std::vector<>, std::list<> and std::forward list<>
2A sequence container provides access based on the position of an element in the sequence.

3An associative container provides access to the elements based on a key.

4The Standard Library offers two categories of associative containers:

Ordered associative containers are usually implemented as Self-balancing binary search trees.
std::set<>, std::multiset<>, std::map<>, and std::multimap<>

Unordered associative containers are implemented as hash tables.
std::unorderedset<>, std::unordered multiset<>, std::unordered map<>, and std::unorderedmultimap<>

2.2            Representation: Class Dog
The following class Dog provides a minimal representation of a dog record:

// Dog.h

#ifndef DOG_H

#define DOG_H

#include <iostream> #include <string> using std::string;

class Dog { string name; string breed; string age; string gender;

public:

Dog() = default; virtual ~Dog() = default; Dog(const Dog&) = default;

        Dog(Dog&&)                  = default;

Dog& operator=(const Dog&) = default;

         Dog& operator=(Dog&&)                    = default;

Dog(string n, string b, string a, string g) : name(n), breed(b), age(a), gender(g) { }

// accessors string getBreed() const { return breed; } string getName()      const { return name; } string getAge()      const { return age; } string getGender() const { return gender; }

// mutators void setBreed(string breed) { this->breed = breed; } void setName(string name)           { this->name = name; } void setAge(string age)               { this->age = age; } void setGender(string gender){ this->gender = gender; }

friend std::ostream& operator<<(std::ostream&, const Dog&); // done friend std::istream& operator>>(std::istream&, Dog&);        // done

};

void trim(string& str); // on your to-do list

#endif /* DOG_H */
1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

2.3            Implementation: Class Dog
// Dog.cpp #include "Dog.h"

std::ostream &operator<<(std::ostream &sout, const Dog &dog) { sout << dog.name << ", " << dog.breed << ", "

<< dog.age << ", " << dog.gender; return sout;

}
1

2

3

4

5

6

7

8

std::istream& operator>>(std::istream& sin, Dog& d) { bool ok = false; if (std::getline(sin, d.name, ’,’)) { trim(d.name); if (std::getline(sin, d.breed, ’,’)) { trim(d.breed); if (std::getline(sin, d.age, ’,’)) { trim(d.age); if (std::getline(sin, d.gender)) { trim(d.gender); ok = true;

}

}

}

} if (!ok && !sin.eof()) { throw std::runtime_error("Invalid input line ");

} return sin;

}
9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

      2.3.1        On your to-do list

Without using explicit loops (for, while, do-while), implement the following trim function to remove whitespace from both ends of a given string str. Hint: use find members of std::string.

void trim( std::string& str) {

// trim leading and trailing whitespaces in str std::string whitespaces(" \t\f\v\n\r"); // ... return;

}
30

31

32

33

34

35

36

2.4            Storage for Dog Records
      2.4.1      Requirements

In this assignment, we are interested in a container that keeps the elements sorted according to a given comparison object, and provides faster than O(n) time for element lookup.

Since the elements in sequence containers are indexed by position, the best they can offer is O(n) and O(nlogn) time for searching and sorting a sequence, respectively.

To do better, we need a container that allows indexing the dog records by a dog’s key attribute such as breed; that is, a container that models a dictionary structure, where key is breed and the associated values are dog records.

Specifically, we need a dictionary container that allows multiple dog records to share the same breed, such as Bull Terrier which appears in two of the records listed in the sample input file shown in 2.1.

Mapping keys to their corresponding values, a dictionary can provide O(logn) operations (lookup/insertion/removal), while keeping the elements ordered based on some policy.

      2.4.2      Representation: DogMap

using
DogMap
=
std::multimap<std::string, Dog>;
// Key type is std::string,
 
 
 
 
// mapped type is Dog
A clear choice of a container from the C++ STL that satisfies the requirements above is a std:: multimap<Key,T> whose elements are of the type std::pair<Key, T>, where Key represents the key type and T represents the mapped type.

We choose std::multimap<Key,T> rather than std::map<Key,T> because dogDB.csv may contain multiple dog records with the same key (breed).

Here is how to insert a Dog object into a DogMap object:

Dog dog("Raven", "Bull Terrier", "12", "Male"); // create a Dog object std::string dog_breed = dog.getBreed(); // get dog’s breed
 
 
// create a DogMap object

DogMap dogmap; // key type is std::string,

// mapped type is Dog
 
 
 
// insert an element into dogmap dogmap.emplace(dog_breed, dog);         // ok, or dogmap.insert({ dog_breed, dog }); // ok
 
dogmap.insert(std::make_pair(dog_breed, dog));                                                          // noisy

dogmap.insert(std::pair<std::string, Dog>(dog_breed, dog)); // noisier

//dogmap[dog_breed] = dog; // only with std::map;

// std::multimap does not support operator[]
2.5            Loading a DogMap Object From a CSV File
using DogMap = std::multimap<std::string, Dog>; void load_DogMap(DogMap& dog_map, std::string cvsfilename)

{ std::ifstream my_file_stream(cvsfilename); // Create an input file stream if (!my_file_stream.is_open()) { cout << "Could not open file " + cvsfilename << endl; throw std::runtime_error("Could not open file " + cvsfilename);

}

std::string line; while (std::getline(my_file_stream, line)) {     // read a line std::stringstream my_line_stream(line); // turn the line into a string stream

                  Dog dog{};                                                  // create a Dog object, and

my_line_stream >> dog; // initialize it using Dog’s extraction operator>> dog_map.emplace(dog.getBreed(), dog); // insert dog into dog_map

} my_file_stream.close(); // close the file stream

}
1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

2.6            Your Tasks
The tasks in this section are independent. Each task starts by asking you to create a new Project initialized with your Task 1 project code; this approach is intended to minimize the potential for introducing conflicting features within the same project.

To facilitate grading, however, please combine some or all of the tasks into a single project as much as possible. Include and submit any remaining code, if any, in a plain dogMapExtra.cpp file, itemizing its contents in your README file.

      2.6.1      Task 1

Create a project named Task 1.

Include the code segment from sections 2, 2.3, and 2.5.
Implement the trim method as specified on page 3, and
Test drive your code as follows:
1

2

3

4

using DogMap = std::multimap<std::string, Dog>; int main()

{

DogMap dogMap{}; string filename{ R"(C:\Users\msi\CPP\Dogs\dogDB.csv)" }; // adjust file path

// to your file load_DogMap(dogMap, filename); cout << dogMap << "==========" << endl;

return 0;

}
according
directory
7

8

9

10

11

      2.6.2       Output of project Task 1

Bracco Italiano --> Nacho, Bracco Italiano, 4, male

Bull Terrier --> Abby, Bull Terrier, 8, Female

Bull Terrier --> Raven, Bull Terrier, 12, Male

Chihuahua --> Toby, Chihuahua, 2, Male

Coton de Tulear --> Nacho, Coton de Tulear, 3, male

Flat-Coated Retriever --> Abby, Flat-Coated Retriever, 1, female

German Shepherd Dog --> Coco, German Shepherd Dog, 13, Female

Stabyhoun --> Piper, Stabyhoun, 9, male

==========
1

2

3

4

5

6

7

8

9

      2.6.3      Task 2

Create a Task 2 project, initializing it with your Task 1 header/implementation files.
Make a copy of the load DogMap function and rename it load DogMap Using For Each. Then replace the explicit while loop in that function using the for each
There is only one version of std::for each, which to be set up according to the comments in the code below:

template <class InputIterator, class Function>

Function for_each (

InputIterator first, // input iterator to the initial Dog object

InputIterator last, // input iterator to the final Dog object

Function fn); // Implement fn as a lambda that takes a Dog as parameter,

// captures the destination multimap by reference, and

// then creates and inserts an element of type

// std::pair<std::string, Dog> into the multimap
Specifically, complete the code below by filling out the blank after line 14 and before return.

1

2

3

using DogMap = std::multimap<std::string, Dog>; void load_DogMap_Using_For_Each(DogMap& dog_map, std::string cvsfilename)

{ std::ifstream input_file_stream(cvsfilename); // Create an input file

if (!input_file_stream.is_open()) {     // Check that the file is open cout << "Could not open file " + cvsfilename << endl; throw std::runtime_error("Could not open file " + cvsfilename);

}

// Get input stream and end of stream iterators std::istream_iterator<Dog> input_stream_begin{ input_file_stream }; std::istream_iterator<Dog> input_stream_end{};

// Copy Dog elements from [input_stream_begin, input_stream_end)

         //                                                        to dog_map using for_each function

// fill in the blank return;

}
              4                                                                                                                                                                                                                                                                                           stream

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

Replace the main() function as follows an then run Task 2:
1

2

3

4

using DogMap = std::multimap<std::string, Dog>; int main()

{

DogMap dogMap{}; string filename{ R"(C:\Users\msi\CPP\Dogs\dogDB.csv)" }; // adjust file path

// to your file load_DogMap_Using_For_Each(dogMap, filename); cout << dogMap << "==========" << endl;

return 0;

}
according
directory
7

8

9

10

11

      2.6.4       Output of project Task 2

Bracco Italiano --> Nacho, Bracco Italiano, 4, male

Bull Terrier --> Abby, Bull Terrier, 8, Female

Bull Terrier --> Raven, Bull Terrier, 12, Male

Chihuahua --> Toby, Chihuahua, 2, Male

Coton de Tulear --> Nacho, Coton de Tulear, 3, male

Flat-Coated Retriever --> Abby, Flat-Coated Retriever, 1, female

German Shepherd Dog --> Coco, German Shepherd Dog, 13, Female

Stabyhoun --> Piper, Stabyhoun, 9, male

==========
10

11

12

13

14

15

16

17

18

      2.6.5      Task 3

Create a Task 3 project, initializing it with your Task 1 header/implementation files.
Make a copy of the load DogMap function, renaming it load DogMap Using Transform. Then replace the explicit while loop in that function using the transform
Use the version of std::transform that takes a unary operation, which to be set up according to the comments in the code below:

template <class InputIterator, class OutputIterator, class UnaryOperation>

OutputIterator transform (

InputIterator first1, // input iterator to the initial Dog object

              InputIterator last1,                            // input iterator to the final Dog object

OutputIterator result, // output iterator into a DogMap, wrapped in an

// for example: std::inserter(dog_map,

UnaryOperation op);

// Implement op as a lambda that takes a Dog as parameter,

// captures its enclosing scope by reference, and then

// creates and returns a std::pair<std::string, Dog> object
inserter dog_map.begin())

Specifically, following the comments above, complete the code below by filling out the blank after line 14 and before return.

1

2

3

using DogMap = std::multimap<std::string, Dog>; void load_DogMap_Using_Transform(DogMap& dog_map, std::string cvsfilename)

{ std::ifstream input_file_stream(cvsfilename); // Create an input file

if (!input_file_stream.is_open()) {     // Check that the file is open cout << "Could not open file " + cvsfilename << endl; throw std::runtime_error("Could not open file " + cvsfilename);

}

// Get input stream and end of stream iterators std::istream_iterator<Dog> input_stream_begin{ input_file_stream }; std::istream_iterator<Dog> input_stream_end{};

// Copy Dog elements from [input_stream_begin, input_stream_end)

         //                                                       to dog_map using std::transform

// fill in the blank return;

}
              4                                                                                                                                                                                                                                                                                           stream

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

Replace the main() function as follows an then run Task 3:
12

13

14

int main()

{ std::multimap<std::string, Dog> dogMap{}; string filename{ R"(C:\Users\msi\CPP\Dogs\dogDB.csv)" }; // adjust file path

// to your file load_DogMap_Using_Transform(dogMap, filename); cout << dogMap << "==========" << endl;

return 0;

}
according
directory
17

18

19

20

21

      2.6.6       Output of project Task 3

Bracco Italiano --> Nacho, Bracco Italiano, 4, male

Bull Terrier --> Abby, Bull Terrier, 8, Female

Bull Terrier --> Raven, Bull Terrier, 12, Male

Chihuahua --> Toby, Chihuahua, 2, Male

Coton de Tulear --> Nacho, Coton de Tulear, 3, male

Flat-Coated Retriever --> Abby, Flat-Coated Retriever, 1, female

German Shepherd Dog --> Coco, German Shepherd Dog, 13, Female

Stabyhoun --> Piper, Stabyhoun, 9, male

==========
19

20

21

22

23

24

25

26

27

      2.6.7      Task 4

The std::multimap class template is prototyped as follows:

template < class Key,
// multimap::key_type
class T,
// multimap::mapped_type
class Compare = less<Key>,
// multimap::key_compare
class Alloc = allocator<pair<const Key,T> >

> class multimap;
// multimap::allocator_type
As you can see, in addition to the key type Key and the mapped type T, there is also a third optional type parameter Compare for key compare and a forth optional type parameter Alloc for allocator type. Unless an application must take charge of its own storage management, the supplied default allocator type is most often the best choice.

However, sometimes you want to supply another Compare type instead of accepting the default std::less<Key>.

Create a Task 4 project, initializing it with your Task 1 header/implementation files.
By default, the standard library uses the operator< for the key type (std::string) to compare the keys (breeds). In this project, let us use std::string’s operator> to compare the keys (breeds) in our dog map. In this entire Task 4 project, replace
using DogMap = std::multimap<std::string, Dog>;

with

using DogMapReversed = std::multimap<std::string, Dog, std::greater<std::string>>;

Run Task 4.
      2.6.8       Output of project Task 4

Stabyhoun --> Piper, Stabyhoun, 9, male

German Shepherd Dog --> Coco, German Shepherd Dog, 13, Female

Flat-Coated Retriever --> Abby, Flat-Coated Retriever, 1, female

Coton de Tulear --> Nacho, Coton de Tulear, 3, male

Chihuahua --> Toby, Chihuahua, 2, Male

Bull Terrier --> Abby, Bull Terrier, 8, Female

Bull Terrier --> Raven, Bull Terrier, 12, Male

Bracco Italiano --> Nacho, Bracco Italiano, 4, male
      2.6.9      Task 5

Create a Task 5 project, initializing it with your Task 1 header/implementation files.
Introduce the following function into your project and then complete it:
using DogMap = std::multimap<std::string, Dog>;

DogMap findBreedRange(const DogMap& source, std::string key_breed)

{ trim(key_breed);

// fill in the blank

// return the resulting DogMap;

}
The function takes a DogMap and a std::string as parameters and returns a DogMap that contains all Dog objects in source having the same key breed. Hint: use equal range 3. Replace your main() with this:

int main()

{ std::multimap<std::string, Dog> dogMap{}; string filename{ R"(C:\Users\msi\CPP\Dogs\dogDB2.csv)" }; // adjust file

// to your file load_DogMap(dogMap, filename);

//cout << dogMap << "==========" << endl;

DogMap brMap1 = findBreedRange(dogMap, std::string("Greyhound")); cout << brMap1 << "----------" << endl;

DogMap brMap2 = findBreedRange(dogMap, std::string("Lakeland Terrier")); cout << brMap2 << "----------" << endl;

DogMap brMap3 = findBreedRange(dogMap, std::string("Pug")); cout << brMap3 << "----------" << endl;

DogMap brMap4 = findBreedRange(dogMap, std::string("Xyz")); cout << brMap4 << "----------" << endl;

return 0;

}
path according directory

Replace the input file with dogDB2.csv:
Tilly, Greyhound, 8, female

Cubby, Pug, 3, Female

Toby, Pug, 5, male

Lacey, Greyhound, 5, Female

Boris, Great Dane, 3, male

Charlie, Greyhound, 5, Male

Meatball, Great Dane, 1, Male

Roxy, Greyhound, 10, female

Patch, Pug, 6, male

Izzy, Greyhound, 5, Male

Hera, Pug, 11, female

Jasper, Greyhound, 13, male

Bella, Great Dane, 11, female

Ollie, Lakeland Terrier, 1, Female

Run your Task 5 project.
2.6.10            Output of project Task 5

Greyhound --> Tilly, Greyhound, 8, female

Greyhound --> Lacey, Greyhound, 5, Female

Greyhound --> Charlie, Greyhound, 5, Male

Greyhound --> Roxy, Greyhound, 10, female

Greyhound --> Izzy, Greyhound, 5, Male

Greyhound --> Jasper, Greyhound, 13, male

----------

Lakeland Terrier --> Ollie, Lakeland Terrier, 1, Female

----------

Pug --> Cubby, Pug, 3, Female

Pug --> Toby, Pug, 5, male

Pug --> Patch, Pug, 6, male

Pug --> Hera, Pug, 11, female

----------

----------
3              Task 6: Palindromes and No Explicit Loops
Recall that a palindrome is a word or phrase that reads the same when read forward or backward, such as “Was it a car or a cat I saw?”. The reading process ignores spaces, punctuation, and capitalization.

Write a function named isPalindrome that receives a string as the only parameter and determines whether that string is a palindrome.

Your implementation may not use

any form of loops explicitly; that is, no for, while or do/while loops
more than one local string variable
raw arrays, STL container classes
3.1            A Suggestion
use std::remove copy if to move only alphabet characters from phrase to temp;
Take into account that temp is initially empty, forcing the need for an inserter iterator!

As the last argument to std::remove copy if, pass a unary predicate, a regular free function, called, say, is alphabetic, that takes a char ch as its only parameter and determines whether ch is an alphabetic character.

To allow case insensitive comparison of characters in temp, convert all the characters in it to the same letter-case, either uppercase or lowercase.
To do this use the std::transform algorithm, passing temp as both the source and the destination streams, effectively overwriting temp during the transformation process.

– Use a lambda as the last argument to transform, defining a function that takes a char ch as its only parameter and returns ch in the selected letter-case.

use std::equal to compare the first half of temp with its second half, moving forward in the first half starting at begin() and moving backward in the second half starting at temp.rbegin().
Set result to the value returned from the call to std::equal; return result

3.2            Driver Function
Use the following function to test your isPalindrome function:

void test_is_palindrome()

{ std::string cat_i_saw = std::string("was it a car or A Cat I saW?"); assert(is_palindrome(cat_i_saw) == true); cout << "the phrase \"" + cat_i_saw + "\" is a palindrome\n";

std::string cat_u_saw = std::string("was it A Car or a cat U saW?"); assert(is_palindrome(cat_u_saw) == false); cout << "the phrase \"" + cat_u_saw + "\" is not a palindrome\n"; }
1

2

3

4

5

6

7

8

9

10

4              Task 7: Searching for Second Max
Write a function template named second max to find the second largest element in a container within a given range [start, finish), where start and finish are iterators that provide properties of forward iterators.

Your function template should be prototyped as follows, and may not use STL algorithms or containers.

template <class Iterator>              // template header std::pair<Iterator,bool>         // function template return type;

second_max(Iterator start, Iterator finish) // function signature {

// your code                                                                                           // function body

}
Clearly, in the case where the iterator range [start, finish) contains at least two distinct objects, second max should return an iterator to the second largest object. However, what should second max return if the iterator range [start, finish) is empty or contains objects which are all equal to one another? How should it convey all that information back to the caller?

Mimicking std::set’s insert member function, your second max function should return a std::pair<Iterator,bool> defined as follows:

4.1            Driver Function
Use the following function to test your second max function:

 

void test_second_max(std::vector<int> vec) {

// note: auto in the following statement is deduced as // std::pair<std::vector<int>::iterator, bool> auto retval = second_max(vec.begin(), vec.end());

if (retval.second)

{ cout << "The second largest element in vec is "

<< *retval.first << endl;

} else { if (retval.first == vec.end()) cout << "List empty, no elements\n";

else cout << "Container’s elements are all equal to "

<< *retval.first << endl; }

}
 

 

5              Task 8: Counting Strings of Equal lengths
Write three wrapper functions with the same return type and parameter lists.

int count_using_xxx (const std::vector<std::string>& vec, int n);
1

where xxx is either lamda, free func, or functor (function object).

Each function must return the number of elements in the vec that are of length n.

For example, suppose

std::vector<std::string> vec { "C", "BB", "A", "CC", "A", "B",

"BB", "A", "D", "CC", "DDD", "AAA", "CCC" };
Then, for example, the call to any of your wrapper functions with the arguments (vec, 1), (vec, 2), (vec, 3), and (vec, 4), should return 6, 4, 3, and 0, respectively.

Your wrapper functions must each use the count if algorithm from <algorithm>.

// Returns the number of elements in the range [first,last) for which pred is true.

template <class InputIterator, class UnaryPredicate>       // template header typename iterator_traits<InputIterator>::difference_type // return type count_if (InputIterator first,        // vec.begin()

                                          InputIterator last,                                                                               // vec.end()

                                        UnaryPredicate pred);                                                                          // a unary predicate
You should implement three versions of the unary predicate, with each version taking a std::string as their only parameter and returning whether or not that std::string is of length n:

version 1: Uses a lambda expression named Lambda that napture n by value in the lambda introducer

int count_using_lambda (const std::vector<std::string>& vec, int n);
2

version 2: Uses a free function bool FreeFun(std::string, int) and then turn it into a “unary” function by fixing its 2nd argument to n using std::bind.

int count_using_Free_Func(const std::vector<std::string>& vec, int n);
3

version 3: Uses a functor (function object) named that stores n at construction.

int count_using_Functor(const std::vector<std::string>& vec, int n);
4

5.1            Driver Function
 

void task_8_test_driver()

{ std::vector<std::string> vecstr

{ "count_if", "Returns", "the", "number", "of", "elements", "in", "the",

"range", "[first", "last)", "for", "which", "pred", "is", "true."

}; cout << count_using_lambda(vecstr, 5) << endl; cout << count_using_Free_Func(vecstr, 5) << endl; cout << count_using_Functor(vecstr, 5) << endl; cout << "\n";

}
 

 

6              Task 9: Sorting Strings on length and Value
Consider the following function that defines a multiset object using std::multiset’s default compare type parameter, which is std::less<T>:

void multisetUsingDefaultComparator()

{ std::multiset<std::string> strSet; // an empty set

// a set that uses the default std::less<int> to sort the set elements std::vector<std::string> vec {"C", "BB", "A", "CC", "A", "B", "BB", "A", "D", "CC", "DDD", "AAA" };

// copy the vector elements to our set.

// We must use a general (as oppsed to a front or back) inserter.

// (set does not have push_front or push_back members,

// so we can’t use a front or back inserter)

                  std::copy(vec.begin(), vec.end(),                                                                    // source start and finish

std::inserter(strSet, strSet.begin())); // destination start with

// a general inserter

// create an ostream_iterator for writing to cout,

// using a space " " as a separator

std::ostream_iterator<std::string> out(cout, " ");

// output the set elements to cout separating them with a space std::copy(strSet.begin(), strSet.end(), out);

}
1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

When called, the function produces the following output:

A A A AAA B BB BB C CC CC D DDD

Renaming the function multisetUsingMyComparator(), modify the declaration on line 3 so that it produces an output like this:

A A A B C D BB BB CC CC AAA DDD

The effect is that the string elements in strSet are now ordered into groups of strings of increasing lengths 1, 2, 3, ..., with the strings in each group sorted lexicographically.

7              Test Driver Function For Tasks 6-9
// test_driver_6789.cpp

// To facilitate marking, Please:

// include appropriate header files

// include prototypes of all functions called in this unit

// include the implementation of all the functions in this file;

// include other types, functors, or function facilitators of your choice in this int main()

{

// Task 6:

test_is_palindrome(); cout << "\n";

// Task 7: std::vector<int> v1{ 1 }; // one element test_second_max(v1);

std::vector<int> v2{ 1, 1 }; // all elements equal test_second_max(v2);

std::vector<int> v3{ 1, 1, 3, 3, 7, 7 }; // at least with two distict elements test_second_max(v3); cout << "\n";

// Task 8:

task_8_test_driver();

// Task 9:

multisetUsingMyComparator(); cout << "\n";

return 0;

}

More products