Professional Documents
Culture Documents
Table of Contents
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.
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;
};
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());
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;
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;
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:
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;
template<class T>
class Odd {
public:
bool operator()(T item) {
if (item % 2 != 0)
return false;
else
return true;
}
};
v[i]=i;
res = std::stable_partition(v.begin(),v.end(),Odd<int>());
std::random_shuffle(v.begin(),v.end());
std::copy(v.begin(),v.end(),
std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;
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;
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;
std::reverse(buf, buf+10);
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());
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;
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.
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>
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;
}
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.
int tab[10];
// initialize
std::generate(tab,tab+10,Rand<int>());
std::sort(tab,tab+10,std::less<int>());
// initialize
std::generate(tab,tab+10,Rand<int>());
std::sort(tab,tab+10,std::greater<int>());
// sort by name
std::sort(v.begin(),v.end(),SortByName());
// sort by id
std::sort(v.begin(),v.end(),SortById());
// sort by dept
std::sort(v.begin(),v.end(),SortByDept());
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.
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.
// initialize
std::generate(tab,tab+10,Rand<int>());
std::partial_sort(tab,tab+3,tab+10,std::greater<int>());
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.
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.
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;
// 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;
// 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;
// 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;
// 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.
p = std::max_element(tab,tab+10);
std::cout << "Max value = " << *p << std::endl;
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>
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;
}