Visual C++ 6 Unleashed

Visual C++ 6 Unleashed

By MICKEY WILLIAMS and David Bennett

Algorithms

STL algorithms are functions that perform operations to the items in one or more containers. These algorithm functions are standalone template functions. Because they are so general, they can be applied to ordinary C++ arrays or containers you create yourself.

Algorithms are written to work on iterators, not components. They are parameterized by iterator types and unattached from the containers they operate on. Thus, all containers of the same iterator category can use the same algorithms. Table 13.5 describes the available algorithms.

Table 13.5. STL Algorithms

Algorithm Description
adjacent_find Locates consecutive pairs of matching elements. A predicate version of the function exists.
binary_search Returns True if a given value resides within a given range. A predicate version of this function exists.
copy Copies objects from one range to another.
copy_backward Copies objects from one range to another, with the destination range receiving the elements in reverse order.
count Returns the number of occurrences of a given value within a sequence.
count_if Returns the number of elements that satisfy a predicate.
equal Returns True if objects in two ranges are equal. A predicate version of this function exists.
equal_range Returns a pair that can be inserted in a sequence, and then preserves the ordering of the sequence. A predicate version of this function exists.
fill Fills all objects within a range of a given value.
fill_n Fills objects to each n in a range from the first object to the nth object.
find Returns an iterator to the first object matching a given value.
find_end Finds the last occurrence of a subsequence.
find_first_of Finds the first element equal to a given value. A predicate version of this function exists.
find_if Returns an iterator to the first object for which the predicate equals True.
for_each Applies a designated operation to each element in a container. It cannot change the contents of each container.
generate Fills all objects within a range with a value generated by the function.
generate_n Fills all objects from the first element to the nth element within a range with a value generated by the function.
includes Returns True if every object of one range is in every object of another range. A predicate version of this function exists.
inplace_merge Merges two sorted subsequences into a single sorted sequence. A predicate version of this function exists.
iter_swap Swaps to elements by their two iterators.
lexicographical_compare Returns True if the sequence of the first range is lexicographically less than the sequence of the second range.
lower_bound Returns the lower bound of a given range.
make_heap Creates a heap out of a given range of values. A predicate exists for this function.
max Returns the largest value of two given objects.
max_element Returns the iterator of the largest element of two given objects. A predicate exists for this function.
merge Merges two ranges into a third range. A predicate version of the function exists.
min Returns the smallest value of two given objects.
min_element Returns the iterator of the smallest element of two given objects. A predicate exists for this function.
mismatch Returns the first pair of corresponding objects that are not equal. A predicate version of this function exists.
next_permutation Changes the order of a sequence to the next lexicographic permutation.
nth_element Partitions elements in a sequence by the given nth element.
partial_sort Sorts only the middle to the beginning of a range. The remaining elements of the range (middle to end) remain in an undefined order.
partial_sort_copy Sorts only the middle to the beginning of a range and copies the resulting partial sort to another sequence.
partition Returns the first element for which the predicate returns False. This algorithm arranges elements in a range, with the elements that returned True for the predicate at the beginning of the sequence.
pop_heap Removes an element from the heap.
prev_permutation Changes the order of a sequence to the previous lexicographic permutation.
push_heap Inserts an element into the heap.
random_shuffle Shuffles the elements in random order. A predicate function exists.
remove Removes all elements from a sequence that match a given value.
remove_copy Copies the elements of a sequence to another sequence, removing any elements that match the given value.
remove_copy_if Copies the elements of a sequence to another sequence, removing any elements that satisfy a predicate.
remove_if Removes all elements of a sequence that satisfy a predicate.
replace Replaces all elements of a sequence that match a given value to a new given value.
replace_copy Copies all elements of a sequence that match a given value to a new given value
replace_copy_if Replaces all elements from a sequence that satisfy a predicate with a given value.
replace_if Replaces all elements of a sequence that satisfy a predicate to a new given value.
reverse Reverses the order of objects in a range.
reverse_copy Copies one range to another, reversing the order.
rotate Rotates the items in a sequence by n positions.
rotate_copy Rotates the items in a sequence by n positions, and copies the results to another sequence of the same size.
search Returns the start position of the match if the second range exists in the first. A predicate function exists.
search_n Returns the start position of the match if the second range exists in the first to the nth object. A predicate function exists.
set_difference Determines differences of elements from two ranges, with the results sorted. A predicate version of this function exists, determining the order of the results.
set_intersection Determines the intersection of elements from two ranges, with the results sorted. A predicate version of this function exists, determining the order of the results.
set_symmetric_difference Determines the symmetric difference of elements from two ranges, with the results sorted. A predicate version of this function exists, determining the order of the results.
set_union Determines the union of elements from two ranges, with the results sorted. A predicate version of this function exists, determining the order of the results.
sort Sorts elements within a range. A predicate version of this function exists.
sort_heap Sorts elements within a heap. A predicate version of this function exists.
stable_partition Partitions a sequence into two groups. The first group is the group of elements that satisfy the predicate. The second group consists of the elements that did not satisfy the predicate.
stable_sort Sorts the elements in a sequence, preserving the relative order for equal elements.
swap Swaps two elements.
swap_ranges Swaps two elements from two ranges.
transform Transforms objects from one range into new objects in a second range.
unique Removes all objects but the first one of equal value. A predicate version of this function exists.
unique_copy Copies objects from one range to another, but only ones of unique values.
upper_bound Returns the lower bound of a given range.

After examining these functions, you may have noticed that the functions mention the term predicate, especially the functions ending in _if.

A predicate is simply another parameter that is included in the calling of the function. A predicate is a power option simply because it enables the developer to write a separate function. This function is applied against every object in the range, and the results are processed as the _if algorithm dictates. The replace_if example later in this chapter demonstrates the use of a predicate.

A few of the most common algorithms are covered in the following sections.

count()

The count() algorithm counts the number of elements that contain a particular value. The function call requires the beginning and ending ranges of the search, plus the value that is to be matched. The following code shows an example:

Example 13.5. Count Example

// Count program example

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std ;

typedef vector<int> INTVECTOR;

void main(){

    int total_count = 0 ;

    INTVECTOR MyVector;

// MyVector will contain [ 1, 2, 2, 3 ]
   MyVector.push_back(1) ;

   MyVector.push_back(2) ;

   MyVector.push_back(2) ;
   MyVector.push_back(3) ;

   //Get total count of 1s
   total_count = count(MyVector.begin(), MyVector.end(), 1);

    cout << "Total Count of 1s = " << total_count << endl;

   //Get total count of 1s
   total_count = count(MyVector.begin(), MyVector.end(), 2);

    cout << "Total Count of 2s = " << total_count << endl;

//Get total count of 3s
  total_count = count(MyVector.begin(), MyVector.end(), 3);

  cout << "Total Count of 3s = " << total_count << endl;

} //END

The output of this program follows:

Total Count of 1s = 1
Total Count of 2s = 2
Total Count of 3s = 1
						

find()

The find() algorithm does pretty much what it says, returning the position of the first element it finds that matches the desired value. The following listing is an example of finding values using vectors:

Example 13.6. Find Example

// Find program example

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std ;

typedef vector<int> INTVECTOR;

void main(){

int *location ;   // stores the position of the first
                 // matching element.

INTVECTOR MyVector;

// MyVector will contain [ 8, 6, 7, 5 ]
   MyVector.push_back(8) ;
   MyVector.push_back(6) ;
   MyVector.push_back(7) ;
   MyVector.push_back(5) ;

//Get Position of number 8 - Should return 0
  location = find (MyVector.begin(), MyVector.end(), 8);

  cout << "Position of 8 is " << location - MyVector.end() + MyVector.size() << endl;

//Get Position of number 6 - Should return 1
  location = find (MyVector.begin(), MyVector.end(), 6);

  cout << "Position of 6 is " << location - MyVector.end() + MyVector.size() << endl;
//Get Position of number 7 - Should return 2
  location = find (MyVector.begin(), MyVector.end(), 7);

  cout << "Position of 7 is " << location - MyVector.end() + MyVector.size() << endl;

//Get Position of number 5 - Should return 3
  location = find (MyVector.begin(), MyVector.end(), 5);

  cout << "Position of 5 is " << location - MyVector.end()x + MyVector.size() << endl;

} //END

The output of this program follows:

Position of 8 is 0
Position of 6 is 1
Position of 7 is 2
Position of 5 is 3

Notice how MyVector.size was used to quickly get the number of elements from the container.

for_each()

The for_each() algorithm enables you to use the values of every item of an object in a relatively easy way. The actual object values themselves cannot be changed, but the resulting values can be obtained for other use. The function that accesses their values and works with them is supplied by the developer.

The following listing takes a list of vector numbers and calls a function to display their value doubled:

Example 13.7. For Each Example

// for_each program example
//
// Functions:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std ;

typedef vector<int> INTVECTOR;

// Function to print out vector values
void unchanged_value(int vector_value)
{
    cout << vector_value << endl;
}

// Function to print out vector values * 2
void double_value(int vector_value)
{
  cout << vector_value * 2 << endl;
}

//Main
void main(){

    INTVECTOR Numbers(5) ;        //Declare 5 vectors of integer

//Set values of Numbers vectors
    Numbers[0] = 0;
    Numbers[1] = 1;
    Numbers[2] = 2;
    Numbers[3] = 3;
    Numbers[4] = 4;

 cout << "Numbers unchanged:" << endl;
 for_each(Numbers.begin(), Numbers.end(), unchanged_value);

 cout << endl;

 cout << "Numbers doubled:" << endl;
 for_each(Numbers.begin(), Numbers.end(), double_value) ;

} //END

The output of this program follows:

Numbers unchanged:
0
1
2
3
4

Numbers doubled:
0
2
4
6
8
						

merge()

The merge() algorithm takes two objects and merges their values into a third object. To do this successfully with vectors, the destination container must have its elements initialized. The following listing merges two number vectors into a destination vector and displays the results:

Example 13.8. Merge Example

// merge program example
//
// Functions:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std ;

typedef vector<int> INTVECTOR;


//Main
void main(){

INTVECTOR Set1(6) ;        //Declare 5 vectors of integer
INTVECTOR Set2(3) ;        //Declare 5 vectors of integer
INTVECTOR Destination(9) ; //Declare 8 vectors of integer
// Iterator is used to loop through the vector.
INTVECTOR::iterator MyIterator;


//Set values of Set1
    Set1[0] = 0;
    Set1[1] = 1;
    Set1[2] = 2;
    Set1[3] = 4;
    Set1[4] = 6;
    Set1[5] = 8;

//Set values of Set2
    Set2[0] = 1;
    Set2[1] = 3;
    Set2[2] = 6;

// Initialize vector Destination
   for(int i = 0; i < 9; i++)
        Destination[i] = 0;
    merge(Set1.begin(), Set1.end(), Set2.begin(), Set2.end(), Destination.begin());

// print content of NumbersDeque
cout << "Merged Results = { " ;
  for(MyIterator = Destination.begin();
    MyIterator != Destination.end();
    MyIterator++)
    cout << *MyIterator << " " ;    cout << " }\n" << endl ;

} //END

The output of this program follows:

Merged Results = { 0 1 1 2 3 4 6 6 8 }

sort()

The sort() algorithm simply sorts a set of objects. The following listing displays the code to achieve the results of a sorted numeric vector:

Example 13.9. Sort Example

//Sort program example
//
// Functions:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std ;

typedef vector<int> INTVECTOR;


//Main
void main(){

INTVECTOR SortSet(7 ) ;        //Declare 7 vectors of integer

// Iterator is used to loop through the vector.
INTVECTOR::iterator MyIterator;


//Set values of SortSet
SortSet[0] = 10;
SortSet[1] = -1;
SortSet[2] = 6;
SortSet[3] = 0;
SortSet[4] = -10;
SortSet[5] = 1;
SortSet[6] = -6;

sort(SortSet.begin(), SortSet.end());

// print content of SortSet
cout << "Sorted Results = { " ;
for(MyIterator = SortSet.begin();
    MyIterator != SortSet.end();
    MyIterator++)
    cout << *MyIterator << " " ;    cout << " }\n" << endl ;

} //END

The output of this program follows:

Sorted Results = { -10 -6 -1 0 1 6 10 }
						

swap()

The swap() algorithm swaps two elements of a set. All that is needed are the two positions of the elements. The following listing demonstrates the swap with a numeric vector:

Example 13.10. Swap Example

//swap program example
//
// Functions:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std ;

typedef vector<int> INTVECTOR;


//Main
void main(){

INTVECTOR SwapSet(5) ;        //Declare 5 vectors of integer

// Iterator is used to loop through the vector.
   INTVECTOR::iterator MyIterator;
//Set values of SwapSet
    SwapSet[0] = 1111;
    SwapSet[1] = 222;
    SwapSet[2] = 555;
    SwapSet[3] = 222;
    SwapSet[4] = 6666;

// print content of SwapSet
cout << "Contents before Swap = { " ;
    for(MyIterator = SwapSet.begin();
    MyIterator != SwapSet.end();
    MyIterator++)
   cout << *MyIterator << " " ;    cout << " }\n" << endl ;

swap(SwapSet[0], SwapSet[4]);

// print content of SwapSet
cout << "Contents after Swap = { " ;
    for(MyIterator = SwapSet.begin();
    MyIterator != SwapSet.end();
    MyIterator++)
    cout << *MyIterator << " " ;    cout << " }\n" << endl ;

} //END

The output of this program follows:

Contents before Swap = { 1111 222 555 222 6666 }
Contents after Swap = { 6666 222 555 222 1111 }
						

Using _if: The replace_if () Algorithm

The replace_if function is a special type of algorithm. Whenever you see an _if at the end of an algorithm, it signals that it can use a function. This extra function is called a predicate.

The listing below demonstrates the use of replace_if function:

Example 13.11. Replace If Example

//replace_if program example
//
// Functions:

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

typedef vector<int> INTVECTOR;


//Main
void main(){

INTVECTOR ReplaceSet(7) ;        //Declare 7 vectors of integer

// Iterator is used to loop through the vector.
    INTVECTOR::iterator MyIterator;

//Set values of ReplaceSet
    ReplaceSet[0] = 5;
    ReplaceSet[1] = 7;
    ReplaceSet[2] = 4;
    ReplaceSet[3] = 3;
    ReplaceSet[4] = 6;
    ReplaceSet[5] = 1;
    ReplaceSet[6] = 0;

// print content of ReplaceSet
cout << "Contents before Replace_If = { " ;
    for(MyIterator = ReplaceSet.begin();
    MyIterator != ReplaceSet.end();
    MyIterator++)
    cout << *MyIterator << " " ;    cout << " }\n" << endl ;

replace_if(ReplaceSet.begin(),ReplaceSet.end(),bind2nd(less<int>(), 5), 0 ) ;

// print content of ReplaceSet
cout << "Contents after Replace_If = { " ;
    for(MyIterator = ReplaceSet.begin();
    MyIterator != ReplaceSet.end();
    MyIterator++)
    cout << *MyIterator << " " ;    cout << " }\n" << endl ;

} //END

The output of this program follows:

Contents before Replace_If = { 5  7 4 3 6 1 0 }
Contents after Replace_If = { 5 7 0 0 6 0 0 }

The previous examples should get you started on how to use the algorithms with the STL. As you can see from Table 13.5, many more algorithms exist.

Reverse Iterator

In this section, you will examine the reverse iterator. This iterator gives you the capability to iterate through a container backward. You might think that to iterate backward, all you would have to do is perform the following code:

// print vectors in reverse order
cout << "Contents reverse in order:" << endl;
   for(MyIterator = SetToReverse.end();
    MyIterator != SetToReverse.begin();
    MyIterator—)
   cout << *MyIterator << endl;

This code will not work with a forward iterator. Forward iterators only support the ++ operator and can only progress forward.

Declaring a reverse iterator looks like this:

INTVECTOR::reverse_iterator MyReverseIterator;

You also must use the member functions rbegin() and rend() when using a reverse iterator. You cannot use these functions with a forward iterator. When using rbegin(), the reverse iterator is starting at the end of the container. The iterator also must be incremented.

The following example shows a forward iterator and a reverse iterator operating on the same set of vectors:

//reverse iterator program example
//
// Functions:

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std ;

typedef vector<int> INTVECTOR;

//Main
void main(){

INTVECTOR SetToReverse(4) ;        //Declare 4 vectors of integer

// Iterator is used to loop through the vector.
INTVECTOR::iterator MyIterator;
INTVECTOR::reverse_iterator MyReverseIterator;
//Set values of SetToReverse
    SetToReverse[0] = 0;
SetToReverse[1] = 1;
SetToReverse[2] = 2;
SetToReverse[3] = 3;

// print vectors in forward order
cout << "Contents iterated in order:" << endl;
   for(MyIterator = SetToReverse.begin();
    MyIterator != SetToReverse.end();
    MyIterator++)
   cout << *MyIterator << endl;
   cout << endl ;

// print vectors in reverse order
cout << "Contents iterated in reverse:" << endl;
   for(MyReverseIterator = SetToReverse.rbegin();
    MyReverseIterator != SetToReverse.rend();
    MyReverseIterator++)
   cout << *MyReverseIterator << endl;
   cout << endl ;

} //END

The output of this program follows:

Contents iterated in order:
0
1
2
3
Contents iterated in reverse:
3
2
1
0

Remember: Even though the reverse iterator is starting at the end of the container, use ++ to iterate through it backward.

Share ThisShare This

Informit Network