You are on page 1of 21

Level 4 - Learning Advanced C++

Table of Contents

1.0 STL Mutating Generic Algorithms ...............................................................2


1.1 The Copy Algorithms ................................................................................2
1.2 The Fill Algorithms.....................................................................................4
1.3 STL Mutating Algorithms: generate ...........................................................4
1.4 partition Algorithms....................................................................................5
1.5 random_shuffle Algorithm .........................................................................7
1.6 remove Algorithm ......................................................................................7
1.7 replace Algorithm.......................................................................................8
1.8 reverse Algorithm ......................................................................................8
1.9 rotate Algorithm .........................................................................................9
1.10 The Swap Algorithms ..............................................................................9
1.11 transform Algorithms .............................................................................10
1.12 unique Algorithms .................................................................................11
1.13 Summary & Exercises ...........................................................................12
2.0 STL Sorting And Numerical Algorithms ...................................................13
2.1 sort Algorithm ..........................................................................................13
2.2 stable_sort ...............................................................................................15
2.3 partial_sort...............................................................................................15
2.4 nth_element.............................................................................................16
2.5 binary_search ..........................................................................................16
2.6 lower_bound & upper_bound...................................................................17
2.7 The Merge Algorithms .............................................................................18
2.8 The Set Algorithms ..................................................................................18
2.9 The Min & Max Algorithms.......................................................................19
2.10 Numerical Algorithms ............................................................................20
2.11 Summary & Exercises ...........................................................................21

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 1
Level 4 - Learning Advanced C++

1.0 STL Mutating Generic Algorithms


In this section we will look at a specific group of STL algorithm collectively called the
Mutating Algorithms. These are algorithms that modify the data within the containers that
they are operating on.

We will start with a quick look at the section objectives and then we will examine each
algorithm. We will present an example of how each algorithm is used. One important
point to note is how function objects are used to tailor the behavior of some of these
algorithms.

We will conclude this section with a quick review of the section objectives and look at a
few exercises and solutions.

Objectives
Upon completing this section you should have an understanding of what generic
algorithms are and specifically what are the mutating algorithms within the STL. You
should be comfortable using these algorithms and how to customize their behavior using
function objects.

1.1 The Copy Algorithms


The copy algorithm copies items from one range to a second range. The copy_backward
algorithm does the same thing except in the reverse order. These algorithms are often
used to shift items to the left (copy) or to the right (copy_backward).

template<class T>
class Print {
public:
Print(const char* sep) : m_sep(sep) {
}
void operator()(T item) {
std::cout << item << m_sep.c_str();
}
private:
std::string m_sep;
};

// copy copies the items in the first range to the destination


// range.
// copy_backward does the same thing but in reverse order

std::vector<int> v(10);
int tab[10] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
std::copy(tab,tab+10,v.begin());

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 2
Level 4 - Learning Advanced C++

std::for_each(v.begin(),v.end(),Print<int>(" "));
std::cout << std::endl;

std::copy_backward(tab,tab+10,v.end());
std::for_each(v.begin(),v.end(),Print<int>(" "));
std::cout << std::endl;

// copy and copy_backward are often used to shift a sequence to


// the left or to the right

// shift a vector to the left

// initialize the vector


std::vector<char> v2;
const char* str = "ABCDEFGHIJ";
std::copy(str,str+10,std::back_inserter(v2));

std::cout << "Before shift left" << std::endl;


std::for_each(v2.begin(),v2.end(),Print<char>(""));
std::cout << std::endl;

std::copy(v2.begin()+1, v2.end(), v2.begin());

std::cout << "After shift left" << std::endl;


std::for_each(v2.begin(),v2.end(),Print<char>(""));
std::cout << std::endl;

// shift the vector to the right

// initialize the vector


std::copy(str,str+10,v2.begin());

std::cout << "Before shift right" << std::endl;


std::for_each(v2.begin(),v2.end(),Print<char>(""));
std::cout << std::endl;

std::copy_backward(v2.begin(), v2.end()-1, v2.end());

std::cout << "After shift right" << std::endl;


std::for_each(v2.begin(),v2.end(),Print<char>(""));
std::cout << std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 3
Level 4 - Learning Advanced C++

1.2 The Fill Algorithms


The fill and fill_n algorithms both initialize a sequence with a value. Using fill we specify
a range and a value. Using fill_n we specify the starting range and a count.

template<class T>
class Print {
public:
Print(const char* sep) : m_sep(sep) {
}
void operator()(T item) {
std::cout << item << m_sep.c_str();
}
private:
std::string m_sep;
};

// Both fill and fill_n are used to initialize a range. Using fill we
// specify the range and the value. Using fill_n we specify the start
// of range and a count.

std::vector<int> v(10);
std::fill(v.begin(),v.end(),-5);
std::for_each(v.begin(),v.end(),Print<int>(" "));
std::cout << std::endl;

std::fill_n(v.begin(),10,-5);
std::for_each(v.begin(),v.end(),Print<int>(" "));
std::cout << std::endl;

1.3 STL Mutating Algorithms: generate


The generate algorithm populates a range with the output of successive calls from a
function or function object. The function generate calls requires no arguments.

template<class T>
class File {
public:
File(const char* file) {
m_in.open(file);
}
~File() {
if (m_in)
m_in.close();
}
T operator()() {
m_in.getline(m_buf, sizeof(m_buf));
T line = m_buf;
return line;
}
private:

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 4
Level 4 - Learning Advanced C++

std::ifstream m_in;
char m_buf[80];
};
// generate is used to populate a range with values based on successive
// calls to a function or function object.

std::vector<std::string> v(10);

std::generate(v.begin(),v.end(),
File<std::string>("c:/temp/items.txt"));

std::for_each(v.begin(),v.end(),Print<std::string>("\n"));
std::cout << std::endl;

1.4 partition Algorithms


The partition algorithms, partition and stable_partition, both rearrange items in a range so
that items that satisfy the predicate function appear first, followed by those that do not.
An iterator is returned that marks this point in the range. stable_partition guarantees not
to alter the relative positions of the items.

template<class T>
class Odd {
public:
bool operator()(T item) {
if (item % 2 != 0)
return false;
else
return true;
}
};

// partition and stable_partition rearrange the items in a range such


// the items that satisfy the predicate function appear first, followed
// by the items that do not. an iterator is returned indicating this
// point in the range. stable_partition additionaly guarantees that the
// relative positions of the items in the sequence will not be altered.
std::vector<int> v;
for(int i=0; i<10; i++)
v.push_back(i);
std::vector<int>::iterator res =
std::partition(v.begin(),v.end(),Odd<int>());

// display each range


std::cout << "first range ";
std::for_each(v.begin(),res,Print<int>(" "));
std::cout << std::endl;

std::cout << "second range ";


std::for_each(res,v.end(),Print<int>(" "));
std::cout << std::endl;

// repeat for stable_partition


for(i=0; i<10; i++)

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 5
Level 4 - Learning Advanced C++

v[i]=i;
res = std::stable_partition(v.begin(),v.end(),Odd<int>());

// display each range


std::cout << "first range ";
std::for_each(v.begin(),res,Print<int>(" "));
std::cout << std::endl;

std::cout << "second range ";


std::for_each(res,v.end(),Print<int>(" "));
std::cout << std::endl;

// repeat using STL components


for(i=0; i<10; i++)
v[i]=i;
res = std::partition(v.begin(),v.end(),
std::bind2nd( std::greater<int>(), 2));

// display each range


std::cout << "first range ";
std::for_each(v.begin(),res,Print<int>(" "));
std::cout << std::endl;

std::cout << "second range ";


std::for_each(res,v.end(),Print<int>(" "));
std::cout << std::endl;

// repeat using STL components


for(i=0; i<10; i++)
v[i]=i;
res = std::partition(v.begin(),v.end(),
std::bind1st( std::greater<int>(), 2));

// display each range


std::cout << "first range ";
std::for_each(v.begin(),res,Print<int>(" "));
std::cout << std::endl;

std::cout << "second range ";


std::for_each(res,v.end(),Print<int>(" "));
std::cout << std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 6
Level 4 - Learning Advanced C++

1.5 random_shuffle Algorithm

The random_shuffle algorithm randomly rearranges the items in a range.

// random_shuffle randomly rearranges the items in a range.


std::vector<int> v;
for(int i=0; i<100; i++)
v.push_back(i);

std::random_shuffle(v.begin(),v.end());

std::copy(v.begin(),v.end(),
std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;

1.6 remove Algorithm


The remove algorithm scans a range moving items of a specified value into one portion
and all others into another. The items are not deleted from the container, which is always
of the same length after a call to remove. To delete the items we would call the containers
erase method.

// The remove algorithm scans a range, moving items of a specified


// value into one portion and all others into the other.
// The items are not deleted from the container, which is
// always of the same length after a call to remove. To delete the
items
// we would call the containers erase method.
int buf[10] = { 2, 5, 3, 5, 4, 5, 6, 6, 5, 5 };

int* res = std::remove(buf, buf+10, 5);

std::cout << "items to keep ";


std::copy(buf, res, std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;

std::cout << "items to remove ";


std::copy(res, buf+10, std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;

// test with vector


std::vector<int> v;
for(int i=0; i<10; i++)
v.push_back(i);

std::cout << "size of v before call to remove " << v.size() <<
std::endl;
std::vector<int>::iterator p = std::remove(v.begin(), v.end(), 5);
std::cout << "size of v after call to remove " << v.size() <<
std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 7
Level 4 - Learning Advanced C++

v.erase(p);
std::cout << "size of v after erase " << v.size() << std::endl;
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout,"
"));
std::cout << std::endl;

1.7 replace Algorithm


The replace algorithm scans a range replacing items that match one value with another.

// The replace algorithm scans a range, replacing items of a specified


// value with an other value.
int buf[10] = { 2, 5, 3, 5, 4, 5, 6, 6, 5, 5 };
std::copy(buf, buf+10, std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;
std::replace(buf, buf+10, 5, 0);
std::copy(buf, buf+10, std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;

1.8 reverse Algorithm


The reverse algorithm reverses the order of the items in a given range.

// The reverse algorithm reverses the order of the items in a given


range.
int buf[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

std::cout << "Before reverse ";


std::copy(buf, buf+10, std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;

std::reverse(buf, buf+10);

std::cout << "After reverse ";


std::copy(buf, buf+10, std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 8
Level 4 - Learning Advanced C++

1.9 rotate Algorithm


The rotate algorithm rotates the items in a given range around a specified position.

// The rotate algorithm rotates the items in a


// given range around a specified position.
int buf[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

std::cout << "Before rotate ";


std::copy(buf, buf+10, std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;

std::rotate(buf, buf+4, buf+10);

std::cout << "After rotate ";


std::copy(buf, buf+10, std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;

1.10 The Swap Algorithms


The swap algorithm swaps two values. The swap_ranges algorithm generalizes this
concept, swapping one range with another.

// The swap function swaps to values


std::string first="Hello";
std::string second="World";
std::cout << first << " " << second << std::endl;
std::swap(first,second);
std::cout << first << " " << second << std::endl;

// The swap_ranges function swaps ranges.


std::list<std::string> ll;
ll.push_front("Homer");
ll.push_front("Marge");
ll.push_front("Bart");

std::vector<std::string> vec;
vec.push_back("Moe");
vec.push_back("Wiggum");
vec.push_back("Burns");

std::swap_ranges(ll.begin(),ll.end(),vec.begin());

std::cout << "List values ";


std::for_each(ll.begin(),ll.end(),Print<std::string>(" "));
std::cout << std::endl;

std::cout << "Vector values ";


std::for_each(vec.begin(),vec.end(),Print<std::string>(" "));
std::cout << std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 9
Level 4 - Learning Advanced C++

1.11 transform Algorithms


The transform algorithm appears in two forms. The first form of the transform algorithm
passes each item in a range to a unary function of which it’s output is stored in an output
range. The second form of transform passes a pair of items from two input ranges to a
binary function of which it’s output is stored in an output range.

// The first form of the transform algorithm passes each item


// in a range to a unary function of which it’s output is stored
// in an output range.
std::vector<std::string> v(3);
std::list<std::string> ll;
ll.push_front("Homer");
ll.push_front("Marge");
ll.push_front("Bart");
std::transform(ll.begin(),ll.end(),v.begin(),Upper<std::string>());
std::cout << "Uppercase names ";
std::for_each(v.begin(),v.end(),Print<std::string>(" "));
std::cout << std::endl;

// The second form of transform passes a pair of items from


// two input ranges to a binary function of which it’s output
// is stored in an output range.
std::list<std::string> ll2;
ll2.push_front("Simpson");
ll2.push_front("Simpson");
ll2.push_front("Simpson");
std::transform(ll.begin(),ll.end(),ll2.begin(),v.begin(),Concat<std::st
ring>(" "));
std::cout << "Concat'ed names ";
std::for_each(v.begin(),v.end(),Print<std::string>("\n"));
std::cout << std::endl;

int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int b[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int c[10];
std::transform(a,a+10,b,c,std::plus<int>());
std::for_each(c,c+10,Print<int>(" "));
std::cout << std::endl;

std::transform(a,a+10,c,std::bind2nd(std::plus<int>(),10));
std::for_each(c,c+10,Print<int>(" "));
std::cout << std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 10
Level 4 - Learning Advanced C++

1.12 unique Algorithms

The unique algorithm looks for consecutive duplicates in a sequence and moves them in a
manner similar to remove. An iterator is returned that specifies the end and the start of
the subsequences. An option binary predicate function object may be supplied to
customize the test.

// The unique algorithm looks for consecutive duplicates in a


// sequence and moves them in a manner similar to remove.
// An iterator is returned that specifies the end and the
// start of the subsequences.
int tab[10] = { 1, 2, 2, 3, 4, 4, 5, 6, 6, 7 };
int* res = std::unique(tab, tab+10);

std::cout << "Unique items ";


std::for_each(tab,res,Print<int>(" "));
std::cout << std::endl;

// Binary predicate function version.


int tab2[10] = { 1, 2, 20, 3, 4, 40, 5, 6, 60, 7 };
res = std::unique(tab2, tab2+10, TheSame<int>());

std::cout << "Unique items ";


std::for_each(tab2,res,Print<int>(" "));
std::cout << std::endl;

int tab3[10] = { 1, 2, 20, 3, 4, 40, 5, 6, 60, 7 };


res = std::unique(tab3, tab3+10);

std::cout << "Unique items ";


std::for_each(tab3,res,Print<int>(" "));
std::cout << std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 11
Level 4 - Learning Advanced C++

1.13 Summary & Exercises


At this point you should have a general understanding of how to use the STL mutating
algorithms and how to tailor their behavior using function objects and adapters.

Exercises
1. Use copy and an input stream iterator to read int’s into a link list.
2. Use copy to display the list on cout using an output iterator.
3. Use transform to multiply each item in the list by 5 using the STL supplied
multiplies function object.

Solution
#pragma warning( disable : 4786 )

#include <iostream>
#include <list>
#include <algorithm>

int main(int argc, char* argv[]) {

std::list<int> l;
std::copy(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::front_inserter(l) );

std::copy(l.begin(), l.end(),
std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;

std::transform(l.begin(),l.end(),l.begin(),
std::bind2nd(std::multiplies<int>(),5));
std::copy(l.begin(), l.end(),
std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;
return 0;
}

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 12
Level 4 - Learning Advanced C++

2.0 STL Sorting And Numerical Algorithms


In this section we will look at a specific group of STL algorithm collectively called the
Sorting & Numerical Algorithms. These are algorithms that we use when we want to
perform sorting or numerical operations on the data.

We will start with a quick look at the section objectives and then we will examine each
algorithm. We will present an example of how each algorithm is used. One important
point to note is how function objects are used to tailor the behavior of some of these
algorithms.

We will conclude this section with a quick review of the section objectives and look at a
few exercises and solutions.

Objectives
Upon completing this section you should have an understanding of what generic
algorithms are and specifically what are the sorting and numerical algorithms within the
STL. You should be comfortable using these algorithms and how to customize their
behavior using function objects.

2.1 sort Algorithm


The sort algorithm sorts the items in a given range. One of the supplied binary predicate
function objects like less<T> may be used or a user supplied one may be provided. The
sort function is based on the quicksort algorithm, which sorts a sequence of length N in
(N log N) time.

// The sort algorithm sorts a sequence based on the supplied


// binary predicate function object.

int tab[10];

// initialize
std::generate(tab,tab+10,Rand<int>());

std::cout << "Unsorted sequence ";


std::for_each(tab,tab+10,Print<int>(" "));
std::cout << std::endl;

std::sort(tab,tab+10,std::less<int>());

std::cout << "Sorted ascending order sequence ";


std::for_each(tab,tab+10,Print<int>(" "));

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 13
Level 4 - Learning Advanced C++

std::cout << std::endl;

// initialize
std::generate(tab,tab+10,Rand<int>());

std::cout << "Unsorted sequence ";


std::for_each(tab,tab+10,Print<int>(" "));
std::cout << std::endl;

std::sort(tab,tab+10,std::greater<int>());

std::cout << "Sorted descending order sequence ";


std::for_each(tab,tab+10,Print<int>(" "));
std::cout << std::endl;

// customize the sort criteria


std::vector<Employee*> v;
v.push_back( new Employee("EEE", "Dept AAA", "Id100") );
v.push_back( new Employee("CCC", "Dept BBB", "Id500") );
v.push_back( new Employee("BBB", "Dept DDD", "Id300") );
v.push_back( new Employee("FFF", "Dept CCC", "Id600") );
v.push_back( new Employee("AAA", "Dept CCC", "Id200") );
v.push_back( new Employee("DDD", "Dept AAA", "Id000") );

std::cout << "Unsorted employees " << std::endl;


std::for_each(v.begin(),v.end(),Print<Employee*>("\n"));
std::cout << std::endl;

// sort by name
std::sort(v.begin(),v.end(),SortByName());

std::cout << "Sorted employees by name " << std::endl;


std::for_each(v.begin(),v.end(),Print<Employee*>("\n"));
std::cout << std::endl;

// sort by id
std::sort(v.begin(),v.end(),SortById());

std::cout << "Sorted employees by id " << std::endl;


std::for_each(v.begin(),v.end(),Print<Employee*>("\n"));
std::cout << std::endl;

// sort by dept
std::sort(v.begin(),v.end(),SortByDept());

std::cout << "Sorted employees by dept " << std::endl;


std::for_each(v.begin(),v.end(),Print<Employee*>("\n"));
std::cout << std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 14
Level 4 - Learning Advanced C++

2.2 stable_sort
The stable_sort algorithm sorts the items in a given range just as sort. In addition it
guarantees that the relative order of equivalent elements will remain the same. As with
sort one of the supplied binary predicate function objects may be used or a user supplied
one may be provided. The stable_sort function sorts a sequence of length N in O(N
(log N)2) time.

// The stable_sort algorithm sorts the items in a given range


// just as sort.In addition it guarantees that the relative
// order of equivalent elements will remain the same.

// sort by name, the by dept


std::sort(v.begin(),v.end(),SortByName());
std::stable_sort(v.begin(),v.end(),SortByDept());
std::cout << "Sorted employees by name then stable sorted by dept "
<< std::endl;
std::for_each(v.begin(),v.end(),Print<Employee*>("\n"));
std::cout << std::endl;

2.3 partial_sort
The partial_sort algorithm allows us to specify the number of elements we want sorted.
This is useful if we do not require that the entire range be sorted.

// The partial_sort algorithm allows us to specify the number


// of elements we want sorted. This is useful if we do not
// require that the entire range be sorted.

// initialize
std::generate(tab,tab+10,Rand<int>());

std::cout << "Unsorted sequence " << std::endl;


std::for_each(tab,tab+10,Print<int>(" "));
std::cout << std::endl;

std::partial_sort(tab,tab+3,tab+10,std::greater<int>());

std::cout << "Partially sorted (top 3) in descending order sequence "


<< std::endl;
std::for_each(tab,tab+10,Print<int>(" "));
std::cout << std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 15
Level 4 - Learning Advanced C++

2.4 nth_element
The nth_element algorithm allows us to place an item in the N-th position if the sequence
was sorted. This save us from having to sort the entire sequence in order to find out what
would be, say the 5th largest item in a list.

// The nth_element algorithm allows us to place an item in the N-th


// position is the sequence was sorted. This save us from having to
// sort the entire sequence in order to find out what would be,
// say the 5th largest item in a list.
double salaries[10] = { 22000.0, 28500.00, 17500.00, 22000.0, 54000.00,
77500.00, 18400.00, 100000.00, 23000.0, 50000.0 };
std::nth_element(salaries, salaries+2, salaries+10,
std::less<double>());
std::cout << "The 3rd top salary is " << salaries[2] << std::endl;
std::cout << std::endl;

2.5 binary_search
The binary_search algorithm allows us to search a sorted sequence of items and rapidly
determine if a specified item is present. For a sorted sequence of N items it requires
O(log N) operations to determine if the item is present. The function returns true or false
depending on whether or not the item is present.

// The binary_search algorithm allows us to search a sorted sequence


// of items and rapidly determine if a specified item is present.
// For a sorted sequence of N items it requires O(log N) operations
// to determine if the item is present. The function returns true or
// false depending on whether or not the item is present.
std::vector<int> keys;
for (int i=0; i<100; i++)
keys.push_back(i);
std::sort(keys.begin(), keys.end(), std::less<int>());

// is item 55 in the sequence?


bool isThere = std::binary_search(keys.begin(), keys.end(), int(55));
if (isThere)
std::cout << "The key 55 is in the sequence" << std::endl;
else
std::cout << "The key 55 is not in the sequence" << std::endl;

// is item 555 in the sequence?


isThere = std::binary_search(keys.begin(), keys.end(), int(555));
if (isThere)
std::cout << "The key 555 is in the sequence" << std::endl;
else
std::cout << "The key 555 is not in the sequence" << std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 16
Level 4 - Learning Advanced C++

2.6 lower_bound & upper_bound


The lower_bound and upper_bound algorithms are used whenever we wish to insert a
new item into a sorted sequence and preserve the sort. They each return an iterator
specifying where the item may be inserted.

// The lower_bound and upper_bound algorithms are used whenever we


// wish to insert a new item into a sorted sequence and preserve the
// sort. They each return an iterator specifying where the item may
// be inserted.
std::list<float> ll;
ll.push_front(70.0f);
ll.push_front(60.0f);
ll.push_front(50.0f);
ll.push_front(30.0f);
ll.push_front(20.0f);
ll.push_front(10.0f);
std::list<float>::iterator iter =
std::lower_bound(ll.begin(), ll.end(), 40.0f);
ll.insert(iter, 40.0f);
std::for_each(ll.begin(), ll.end(), Print<float>(" "));
std::cout << std::endl;

std::list<float> ll2;
ll2.push_front(70.0f);
ll2.push_front(60.0f);
ll2.push_front(50.0f);
ll2.push_front(30.0f);
ll2.push_front(20.0f);
ll2.push_front(10.0f);
std::list<float>::iterator iter2 =
std::upper_bound(ll2.begin(), ll2.end(), 40.0f);
ll2.insert(iter2, 40.0f);
std::for_each(ll2.begin(), ll2.end(), Print<float>(" "));
std::cout << std::endl;

equal_range Algorithm
The equal_range algorithm returns a pair of iterators that correspond to what would have
been returned via calls to lower_bound and upper_bound.
std::list<float> ll3;
ll3.push_front(70.0f);
ll3.push_front(60.0f);
ll3.push_front(50.0f);
ll3.push_front(30.0f);
ll3.push_front(20.0f);
ll3.push_front(10.0f);
std::pair< std::list<float>::iterator, std::list<float>::iterator > res
=
std::equal_range(ll3.begin(), ll3.end(), 40.0f);
std::cout << *res.first << " " << *res.second << std::endl;
std::cout << std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 17
Level 4 - Learning Advanced C++

2.7 The Merge Algorithms


The merge algorithms are used to merge two sorted lists into a single merged list. The
inplace_merge algorithm merges consecutive merged ranges in-place to create a single
merged list.

// The merge algorithms are used to merge two sorted lists into a
// single merged list. The inplace_merge algorithm merges consecutive
// merged ranges in-place to create a single merged list.
int tab1[5] = { 10, 20, 30, 40, 50 };
int tab2[5] = { 5, 15, 25, 35, 45 };
int tab3[10];
std::merge(tab1,tab1+5,tab2,tab2+5,tab3);
std::cout << "The merged list ";
std::for_each(tab3,tab3+10,Print<int>(" "));
std::cout << std::endl;

int tab4[10] = { 10, 20, 30, 40, 50, 5, 15, 25, 35, 45 };
std::inplace_merge(tab4,tab4+5,tab4+10);
std::cout << "The in-place merged list ";
std::for_each(tab4,tab4+10,Print<int>(" "));
std::cout << std::endl;

2.8 The Set Algorithms


The set algorithms allow set operations on sorted sequences, these include:
• set_union returns the union of two sets.
• set_intersection returns the intersection of two sets.
• set_difference returns the items contained in the first sequence but not contained
in the second.
• set_symmetric_difference returns the items contained in either sequence but not in
both.
• checks if one sequence appears within another and returns true or false
accordingly.

// The set algorithms allow set operations on sorted sequences.


int tab1[5] = { 10, 20, 30, 40, 50 };
int tab2[5] = { 10, 25, 30, 45, 50 };
int tab3[10];

// union
int* p = std::set_union(tab1,tab1+5,tab2,tab2+5,tab3);
std::cout << "Union ";
std::for_each(tab3,p,Print<int>(" "));
std::cout << std::endl;

// intersection
p = std::set_intersection(tab1,tab1+5,tab2,tab2+5,tab3);
std::cout << "Intersection ";
std::for_each(tab3,p,Print<int>(" "));
std::cout << std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 18
Level 4 - Learning Advanced C++

// difference
p = std::set_difference(tab1,tab1+5,tab2,tab2+5,tab3);
std::cout << "Difference ";
std::for_each(tab3,p,Print<int>(" "));
std::cout << std::endl;

// symmetric difference
p = std::set_symmetric_difference(tab1,tab1+5,tab2,tab2+5,tab3);
std::cout << "Symmetric difference ";
std::for_each(tab3,p,Print<int>(" "));
std::cout << std::endl;

int tab4[3] = { 20, 30, 40 };


bool res = std::includes(tab1,tab1+5,tab4,tab4+3);
if (res)
std::cout << "Located the sequence in tab4 within tab1"
<< std::endl;
else
std::cout << "The sequence in tab4 is not located within tab1"
<< std::endl;

2.9 The Min & Max Algorithms


The min_element and max_element functions find the minimum or maximum value
within an input sequence. They return an iterator indicating the location of the item.

// The min and max functions are given two values and they return the
// minimum or the maximum value respectively. The min_element and
// max_element functions find the minimum or maximum value within an
// input sequence. They return an iterator indicating the location of
// the item.

int tab[10] = { 2, 4, 6, 1, 3, 5, 8, 7, 9, 100 };


int* p = std::min_element(tab,tab+10);
std::cout << "Min value = " << *p << std::endl;

p = std::max_element(tab,tab+10);
std::cout << "Max value = " << *p << std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 19
Level 4 - Learning Advanced C++

2.10 Numerical Algorithms


The STL numerical algorithms include:

• accumulate algorithm adds up the values in the given range.


• partial_sum algorithm computes the partial sum in-place or in another range.
• adjacent_difference algorithm computes the adjacent difference in-place or in
another range.
• inner_product algorithm computes the sums of the products of each element
within two sequences.

// The accumulate algorithm adds up the values in the given range.


int tab[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int sum = std::accumulate(tab,tab+10,0);
std::cout << "Accumulated total = " << sum << std::endl;

// The partial_sum algorithm computes the partial sum in-place


// or in another range.
int tab[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::partial_sum(tab,tab+10,tab);
std::cout << "Partial sum ";
std::for_each(tab,tab+10,Print<int>(" "));
std::cout << std::endl;

// The adjacent_difference algorithm computes the adjacent difference


// in-place or in another range.
std::adjacent_difference(tab,tab+10,tab);
std::cout << "Adjacent difference ";
std::for_each(tab,tab+10,Print<int>(" "));
std::cout << std::endl;

// The inner_product algorithm computes the sums of the products


// of each element within two sequences.
int tab1[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int tab2[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int sum = std::inner_product(tab1,tab1+10,tab2,0);
std::cout << "Inner product = " << sum << std::endl;

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 20
Level 4 - Learning Advanced C++

2.11 Summary & Exercises


At this point you should have a general understanding of how to use the STL sorting and
numerical algorithms and how to tailor their behavior using function objects and
adapters.

Exercises
1. Use copy and an input stream iterator to read int’s into a deque.
2. Use copy to display the items on cout using an output iterator.
3. Sort the items in ascending and descending order.

Solutions
#pragma warning( disable : 4786 )

#include <iostream>
#include <deque>
#include <algorithm>
#include <functional>

int main(int argc, char* argv[]) {

std::deque<int> d;

std::copy(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::front_inserter(d) );

std::copy(d.begin(), d.end(),
std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;

std::sort(d.begin(),d.end(),std::less<int>());
std::copy(d.begin(), d.end(),
std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;

std::sort(d.begin(),d.end(),std::greater<int>());
std::copy(d.begin(), d.end(),
std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;

return 0;
}

Copyright  2001 by Keystone Learning Systems Corp. All rights reserved.


Level 4 - Learning Advanced C++ 21

You might also like