Figure 16.5 demonstrates several common mathematical algorithms, including random_shuffle
, count
, count_if
, min_element
, max_element
, minmax_element
, accumulate
, for_each
and transform
.
1 // Fig. 16.5: fig16_05.cpp
2 // Mathematical algorithms of the Standard Library.
3 #include <iostream>
4 #include <algorithm> // algorithm definitions
5 #include <numeric> // accumulate is defined here
6 #include <array>
7 #include <iterator>
8 using namespace std;
9
10 bool greater9( int ); // predicate function prototype
11 void outputSquare( int ); // output square of a value
12 int calculateCube( int ); // calculate cube of a value
13
14 int main()
15 {
16 const size_t SIZE = 10;
17 array< int, SIZE > a1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
18 ostream_iterator< int > output( cout, " " );
19
20 cout << "a1 before random_shuffle: ";
21 copy( a1.cbegin(), a1.cend(), output );
22
23 random_shuffle( a1.begin(), a1.end() ); // shuffle elements of a1
24 cout << "
a1 after random_shuffle: ";
25 copy( a1.cbegin(), a1.cend(), output );
26
27 array< int, SIZE > a2 = { 100, 2, 8, 1, 50, 3, 8, 8, 9, 10 };
28 cout << "
a2 contains: ";
29 copy( a2.cbegin(), a2.cend(), output );
30
31 // count number of elements in a2 with value 8
32 int result = count( a2.cbegin(), a2.cend(), 8 );
33 cout << "
Number of elements matching 8: " << result;
34
35 // count number of elements in a2 that are greater than 9
36 result = count_if( a2.cbegin(), a2.cend(), greater9 );
37 cout << "
Number of elements greater than 9: " << result;
38
39 // locate minimum element in a2
40 cout << "
Minimum element in a2 is: "
41 << *( min_element( a2.cbegin(), a2.cend() ) );
42
43 // locate maximum element in a2
44 cout << "
Maximum element in a2 is: "
45 << *( max_element( a2.cbegin(), a2.cend() ) );
46
47 // locate minimum and maximum elements in a2
48 auto minAndMax = minmax_element( a2.cbegin(), a2.cend() );
49 cout << "
The minimum and maximum elements in a2 are "
50 << *minAndMax.first << " and " << *minAndMax.second
51 << ", respectively";
52
53 // calculate sum of elements in a1
54 cout << "
The total of the elements in a1 is: "
55 << accumulate( a1.cbegin(), a1.cend(), 0 );
56
57 // output square of every element in a1
58 cout << "
The square of every integer in a1 is:
";
59 for_each( a1.cbegin(), a1.cend(), outputSquare );
60
61 array< int, SIZE > cubes; // instantiate cubes
62
63 // calculate cube of each element in a1; place results in cubes
64 transform( a1.cbegin(), a1.cend(), cubes.begin(), calculateCube );
65 cout << "
The cube of every integer in a1 is:
";
66 copy( cubes.cbegin(), cubes.cend(), output );
67 cout << endl;
68 } // end main
69
70 // determine whether argument is greater than 9
71 bool greater9( int value )
72 {
73 return value > 9;
74 } // end function greater9
75
76 // output square of argument
77 void outputSquare( int value )
78 {
79 cout << value * value << ' ';
80 } // end function outputSquare
81
82 // return cube of argument
83 int calculateCube( int value )
84 {
85 return value * value * value;
86 } // end function calculateCube
a1 before random_shuffle: 1 2 3 4 5 6 7 8 9 10
a1 after random_shuffle: 9 2 10 3 1 6 8 4 5 7
a2 contains: 100 2 8 1 50 3 8 8 9 10
Number of elements matching 8: 3
Number of elements greater than 9: 3
Minimum element in a2 is: 1
Maximum element in a2 is: 100
The minimum and maximum elements in a2 are 1 and 100, respectively
The total of the elements in a1 is: 55
The square of every integer in a1 is:
81 4 100 9 1 36 64 16 25 49
The cube of every integer in a1 is:
729 8 1000 27 1 216 512 64 125 343
Line 23 uses the random_shuffle algorithm to reorder randomly the elements in the range a1.begin()
up to, but not including, a1.end()
. This algorithm takes two random-access iterator arguments. This version of random_shuffle
uses rand for randomization and produces the same results each time you run the program unless you seed the random-number generator with srand
. Another version of random_shuffle
receives as its third argument a C++11 uniform random-number generator.
Line 32 uses the count algorithm to count the elements with the value 8
in the range a2.cbegin()
up to, but not including, a2.cend()
. This algorithm requires its two iterator arguments to be at least input iterators.
Line 36 uses the count_if algorithm to count elements in the range from a2.cbegin()
up to, but not including, a2.cend()
for which the predicate function greater9
returns true
. Algorithm count_if
requires its two iterator arguments to be at least input iterators.
Line 41 uses the min_element algorithm to locate the smallest element in the range from a2.cbegin()
up to, but not including, a2.cend()
. The algorithm returns a forward iterator located at the first smallest element, or a2.end()
if the range is empty. The algorithm’s two iterator arguments must be at least forward iterators. A second version of this algorithm takes as its third argument a binary function that compares two elements in the sequence. This algorithm returns the bool
value true
if the first argument is less than the second.
Error-Prevention Tip 16.1
It’s a good practice to check that the range specified in a call to min_element is not empty and that the return value is not the “past the end” iterator.
Line 45 uses the max_element algorithm to locate the largest element in the range from a2.cbegin()
up to, but not including, a2.cend()
. The algorithm returns a forward iterator located at the first largest element. The algorithm’s two iterator arguments must be at least forward iterators. A second version of this algorithm takes as its third argument a binary predicate function that compares the elements in the sequence. The binary function takes two arguments and returns the bool
value true
if the first argument is less than the second.
Line 48 uses the new C++11 minmax_element algorithm to locate both the smallest and largest elements in the range from a2.cbegin()
up to, but not including, a2.cend()
. The algorithm returns a pair of forward iterators located at the smallest and largest elements, respectively. If there are duplicate smallest or largest elements, the iterators are located at the first smallest and last largest values. The algorithm’s two iterator arguments must be at least forward iterators. A second version of this algorithm takes as its third argument a binary predicate function that compares the elements in the sequence. The binary function takes two arguments and returns the bool
value true
if the first argument is less than the second.
Line 55 uses the accumulate algorithm (the template of which is in header <numeric>
) to sum the values in the range from a1.cbegin()
up to, but not including, a1.cend()
. The algorithm’s two iterator arguments must be at least input iterators and its third argument represents the initial value of the total. A second version of this algorithm takes as its fourth argument a general function that determines how elements are accumulated. The general function must take two arguments and return a result. The first argument to this function is the current value of the accumulation. The second argument is the value of the current element in the sequence being accumulated.
Line 59 uses the for_each algorithm to apply a general function to every element in the range from a1.cbegin()
up to, but not including, a1.cend()
. The general function takes the current element as an argument and may modify that element (if it’s received by reference and is not const
). Algorithm for_each
requires its two iterator arguments to be at least input iterators.
Line 63 uses the transform algorithm to apply a general function to every element in the range from a1.cbegin()
up to, but not including, a1.cend()
. The general function (the fourth argument) should take the current element as an argument, must not modify the element and should return the transform
ed value. Algorithm transform
requires its first two iterator arguments to be at least input iterators and its third argument to be at least an output iterator. The third argument specifies where the transform
ed values should be placed. Note that the third argument can equal the first. Another version of transform
accepts five arguments—the first two arguments are input iterators that specify a range of elements from one source container, the third argument is an input iterator that specifies the first element in another source container, the fourth argument is an output iterator that specifies where the transformed values should be placed and the last argument is a general function that takes two arguments. This version of transform
takes one element from each of the two input sources and applies the general function to that pair of elements, then places the transformed value at the location specified by the fourth argument.