Algorithms

There are 60 algorithms in the standard library. Programs that use them must include the <algorithm> header file:

#include <algorithm>
using namespace std;

Finders

The standard library provides a family of finders (find algorithms): find(), find_if(), find_firtst_of(), adjacent_find(), find_end(), search(), and search_n(). The basic finder expects a pair of iterators and a value as input, and returns an iterator pointing to the first element in the sequence matching the value. If the value isn't found, the last iterator is returned:

template<class InIt, class T>
InIt find(InIt first, InIt last, const T& val);

The typename Qualifier

Let's develop a simple template function that determines if a given storable is a member of a given store. For example, if the store is a deque, the function looks like this:

template <class Storable>
bool member(Storable s, deque<Storable> c)
{
   deque<Storable>::iterator p;
   p = find(c.begin(), c.end(), s);
   return (p != c.end());
}

The corresponding functions for lists and vectors are identical except the two occurrences of "deque" must be replaced by "list" and "vector" respectively. We could try to make the store a template parameter, too:

template <class Store, class Storable>
bool member(Storable s, Store c)
{
   Store::iterator p;
   p = find(c.begin(), c.end(), s);
   return (p != c.end());
}

Unfortunately, a subtle ambiguity arises here. We could put redundant parenthesis around p in its declaration:

Store::iterator (p);

Now it's not clear if iterator is a static member function of Store or a type defined in Store. The policy of the C++ compiler is to always assume it is not a type. To get around this problem, we can use the typename qualifier:

template <class Store, class Storable>
bool member(Storable s, Store c)
{
   typename Store::iterator p;
   p = find(c.begin(), c.end(), s);
   return (p != c.end());
}

We could try to use this trick to unify our growing family of writers:

template <class Store, class Storable>
ostream& operator<<(ostream& os, const Store& v)
{
   os << "( ";
   typename Store::const_iterator p;
   for( p = v.begin(); p != v.end(); p++)
      os << *p << ' ';
   os << ")";
   return os;
}

Unfortunately, this makes operator<< too overloaded.

The typename qualifier can also be used instead of class to declare template parameters:

template <typename Storable, int Size>
class Stack
{
   Storable vals[Size];
   int sp; // stack pointer
public:
   // etc.
};

To demonstrate that algorithms can be used with ordinary arrays, too, let's use find() to implement a template function that computes the index of the first occurrence of a given element:

template <class Value>
int findIndex(Value v, Value vals[], int size)
{
   Value* p = find(vals, vals + size, v);
   if (p < vals + size)
      return p - vals;
   else
      return -1;
}

Here's a test harness for our template functions:

#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
#include <functional>
using namespace std;

void testFind()
{
   vector<int> n(10);
   for(int i = 0; i < 10; i++) n[i] = 2 * i + 1;
   cout << n << '\n';
   vector<int>::iterator p;
   cout << "member(3, n) = " << member(3, n) << '\n';
   cout << "member(14, n) = " << member(14, n) << '\n';

   list<string> s;
   for(i = 0; i < 10; i++)
      s.push_back(toString(2 * i + 1));
   cout << s << '\n';
   cout << "member(\"3\", s) = " << member("3", s) << '\n';
   cout << "member(\"4\", s) = " << member("4", s) << '\n';

   int x[10];
   for(i = 0; i < 10; i++)
      x[i] = 2 * i + 1;
   cout << "findIndex(5, x, 10) = " << findIndex(5, x, 10) << '\n';
   cout << "findIndex(6, x, 10) = " << findIndex(6, x, 10) << '\n';

}

Here's the program output:

( 1 3 5 7 9 11 13 15 17 19 )
member(3, n) = 1
member(14, n) = 0
( 1 3 5 7 9 11 13 15 17 19 )
member("3", s) = 1
member("4", s) = 0
findIndex(5, x, 10) = 2
findIndex(6, x, 10) = -1

for_each()

The for_each() algorithm expects a pair of iterators and a unary callable as input. The algorithm applies the unary callable to each element of the sequence delimited by the iterators. The values returned by the callable are discarded, so only side effects of the callable are of interest.

Let's combine a demonstration of this algorithm with another demonstration of the mem_fun() adapter. Assume the following hierarchy of classes is defined:

class Employee
{
public:
   Employee(double s = 0) { salary = s; }
   virtual int print() = 0;
   virtual bool happy() = 0;
   virtual int giveRaise() = 0;
protected:
   double salary;
};

class Executive: public Employee
{
public:
   Executive(): Employee(100000.00) {}
   int print()
   {
      cout << "I'm a lazy executive. ";
      cout << "My salary = " << salary;
      cout << ". Yeah!\n";
      return 0;
   }
   bool happy() { return true; }
   int giveRaise() { salary += salary * .2; return 0; }
};

class Secretary: public Employee
{
public:
   Secretary(): Employee(30000.00) {}
   int print()
   {
      cout << "I'm a hard working secretary. ";
      cout << "My salary = " << salary;
      cout << ". So what?\n";
      return 0;
   }
   bool happy() { return false; }
   int giveRaise() { salary += salary * .1; return 0;};
};

class Programmer: public Employee
{
public:
   Programmer(): Employee(10000.00) {}
   int print()
   {
      cout << "I'm a lowly programmer. ";
      cout << "My salary = " << salary;
      cout << ". Boo hoo!\n";
      return 0;
   }
   bool happy() { return false; }
   int giveRaise() { salary += salary * .05; return 0; }
};

Next, create a list of Employee pointers:

list<Employee*> emps;
emps.push_back(new Programmer());
emps.push_back(new Secretary());
emps.push_back(new Executive());
emps.push_back(new Executive());
emps.push_back(new Executive());
emps.push_back(new Programmer());
emps.push_back(new Secretary());
emps.push_back(new Programmer());

The print() and giveRaise() member functions produce interesting side effects. (The for_each() algorithm seemed to require that they return a value of some sort). We would like to apply these functions to each employee in the list, but they are member functions, so we must first use the mem_fun() adapter to convert them into member functors.

We can give each employee a raise, then print the list as follows:

for_each(emps.begin(), emps.end(), mem_fun(&Employee::giveRaise));
for_each(emps.begin(), emps.end(), mem_fun(&Employee::print));

Here's the print out produced:

I'm a lowly programmer. My salary = 10500. Boo hoo!

I'm a hard working secretary. My salary = 33000. So what?
I'm a lazy executive. My salary = 120000. Yeah!
I'm a lazy executive. My salary = 120000. Yeah!
I'm a lazy executive. My salary = 120000. Yeah!
I'm a lowly programmer. My salary = 10500. Boo hoo!
I'm a hard working secretary. My salary = 33000. So what?
I'm a lowly programmer. My salary = 10500. Boo hoo!

Notice that  runtime variant selection was performed. Although only &Employee::print and &Employee::giveRaise were supplied to for_each(), different variants (e.g., Programmer::print(), Secretary::print(), Executive::print() were called!

If giveRaise() expected a parameter. For example:

int giveRaise(double bonus = 0);

Then we might try to give raises with a fixed $100.00. bonus to each employee as follows:

   for_each(emps.begin(), emps.end(),                            bind2nd(mem_fun1(&Employee::giveRaise), 100.00));

Unfortunately, this didn't work in VC++.  The bind2nd() binder expects the first parameter, in this case the implicit parameter, this, to be constant. In other words, we would need to declare giveRaise() as:

int giveRaise(double bonus = 0) const = 0;

but then salary can't be updated.

Conditionals: count_if(), find_if(), remove_if(), and replace_if()

How many employees are happy? Who are they? How can we get rid of them? The standard library provides two counters. The count() algorithm counts the number of occurrences of a given item in a sequence. The count_if() algorithm counts all those occurrences satisfying a condition specified by a callable predicate. (A predicate is a function or functor that returns a bool.). For example:

list<Employee*>::iterator p = emps.begin(), q = emps.end();

cout << count_if(p, q, mem_fun(&Employee::happy));
cout << " are happy\n";

Let's reinitialize p and print a list of all these smug fat cats. We'll use the find_if() algorithm mentioned earlier:

p = emps.begin(); // necessary?
while(p != q)
{
   p = find_if(p, q, mem_fun(&Employee::happy));
   if (p != q)
   {
      (*p)->print();
      p++;
   }
}

The remove_if() algorithm removes all members of a sequence satisfying a condition specified by a given predicate:

remove_if(emps.begin(), emps.end(),  mem_fun(&Employee::happy));

Now lets count how many are still smiling:

cout << count_if(p, emps.end(), mem_fun(&Employee::happy));
cout << " are happy\n";

Here's the output produced by these calls:

3 are happy

I'm a lazy executive. My salary = 120000. Yeah!

I'm a lazy executive. My salary = 120000. Yeah!

I'm a lazy executive. My salary = 120000. Yeah!

0 are happy

This operation is so useful, we might consider making our own template function. We have to be careful, though. The remove_if() algorithm doesn't alter the length of the sequence, so noisy elements in the tail of a sequence are still there. We must explicitly remove them using the erase function:

template <class Predicate, class Store>

inline void filter(Predicate pred, Store& s)

{

   s.erase(remove_if(s.begin(), s.end(), pred), s.end());

}

The standard library also provides an algorithm that performs conditional replacements. For example, suppose we define a predicate that determines if a given integer is even:

bool even(int n) { return n % 2 == 0; }

We can fill a vector with integers from 0 to 9, then replace each even by 0 with the following calls:

vector<int> n(10);

for(int i = 0; i < 10; i++) n[i] = i;

cout << n << '\n';

replace_if(n.begin(), n.end(), even, 0);

cout << n << '\n;

Here's the output produced:

( 0 1 2 3 4 5 6 7 8 9 )

( 0 1 0 3 0 5 0 7 0 9 )

Transformers

The transform() algorithm is useful but its mysterious third parameter makes it a bit awkward.

template<class InIt, class OutIt, class Unop>
OutIt transform(InIt first, InIt last, OutIt x, Unop uop);

An amplifier is a filter that transforms each member of its input sequence:

template <class Callable, class Store>
inline void amplify(Callable uop, Store& s)
{
   transform(s.begin(), s.end(), s.begin(), uop);
}

Assume a squaring function has been defined:

double square(double x) { return x * x; }

We can "amplify" each element in a sequence by squaring it:

deque<int> d;
for(int i = 0; i < 5; i++)
   d.push_back(i);
cout << d << '\n';
amplify(square, d);
cout << d << '\n';

Here's the output produced:

( 0 1 2 3 4 )
( 0 1 4 9 16 )

We can put all our templates together to build a pipe and filter style function that sums the squares of even integers in a vector:

int sos(vector<int> v)
{
   filter(even, v);
   amplify(square, v);
   return accum(plus<double>(), 0, v);
}