ppt

advertisement
The C++ Algorithm Libraries
• A standard collection of generic algorithms
– Applicable to various types and containers
• E.g., sorting integers (int) vs. intervals (pair<int, int>)
• E.g., sorting elements in a vector vs. in a C-style array
– Polymorphic even without inheritance relationships
• Types substituted need not have a common base class
• Must only provide the operators the algorithm needs
• Significantly used with the sequence containers
– To reorder elements within a container’s sequence
– To store/fetch values into/from a container
– To calculate various values and properties from it
CSE 332: C++ Algorithms I
Motivating Example: Searching a String
• From Austern: “Generic Programming and the STL”
• Sequential (linear) search: find char c in string s
char * strchr (char* s, char c)
{
while (*s != 0 && *s != c){
++s;
}
return *s == c ? s : (char *) 0;
}
• Problem: not very general
– “Range” of iteration is always defined up to ‘\0’ character
– Only works for a “zero terminated” string in C/C++
CSE 332: C++ Algorithms I
Improving Linear Search with Ranges
• First generalization (Austern, pp. 11): use a range
(something that sequential containers can give us!)
char * find1 (char* first, char* last,
char c){
while (first != last && *first != c)
++first;
return first;
}
• Gives an explicit range (calculate its length – how?)
• Assumes first is before last (can check – how?)
• Note how caller checks for success changed: why?
CSE 332: C++ Algorithms I
Linear Search over Parameterized Types
• Second generalization: use templates to parameterize
the function argument types
template <typename T>
T * find2(T * first, T * last, const T & value){
while (first != last && *first != value)
++first;
return first;
}
• How much did the find1 code need to change?
• One last problem
– What if we want to apply this to a container (e.g., list)
whose range can’t be traversed via simple pointers?
CSE 332: C++ Algorithms I
Linear Search with Generic Iterators
• Third generalization: separate iterator type parameter
• We arrive at the find algorithm (Austern pp. 13):
template <typename Iterator, typename T>
Iterator find (Iterator first, Iterator last,
const T & value) {
while (first != last && *first != value)
++first;
return first;
}
• Notice how algorithm depends on the iterators
• Notice how refinements made algorithm more abstract
– … but still essentially does the same thing
– i.e., algorithm structure (and time complexity) is the same
CSE 332: C++ Algorithms I
Organization of C++ Algorithm Libraries
• The <algorithm> header file contains
– Non-modifying sequence operations
• Do some calculation but don’t change sequence itself
• Examples include count, count_if
– Mutating sequence operations
• Modify the order or values of the sequence elements
• Examples include copy, random_shuffle
– Sorting and related operations
• Modify the order in which elements appear in a sequence
• Examples include sort, next_permutation
• The <numeric> header file contains
– General numeric operations
• Scalar and matrix algebra, especially used with vector<T>
• Examples include accumulate, inner_product
CSE 332: C++ Algorithms I
Example of Using Non-Modifying Algorithms
• count algorithm
– Moves through
iterator range
– Checks each
position for
equality
– Increases
count if equal
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main (int, char * []) {
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(2);
int i = 7;
cout << i << " appears " << count(v.begin(), v.end(), i)
<< " times in v" << endl;
/* output is
7 appears 0 times in v
2 appears 2 times in v
*/
i = 2;
cout << i << " appears " << count(v.begin(), v.end(), i)
<< " times in v" << endl;
return 0;
}
CSE 332: C++ Algorithms I
Example of Using Mutating Algorithms
• copy algorithm
ifstream input_file
(input_file_name.c_str());
ofstream output_file
(output_file_name.c_str());
– Copies from an input iterator
range into an output iterator
– Note use of default constructor
to get an “off-the-end” (here,
“end-of-file”) input iterator
– Note use of noskipws (need to
make sure container behavior
matches what you want to do)
#include
#include
#include
#include
#include
input_file >> noskipws;
istream_iterator<char> i (input_file);
ostream_iterator<char> o (output_file);
copy (i, istream_iterator<char>(), o);
<iostream>
<string>
<fstream>
<iterator>
<algorithm>
cout <<
<<
<<
<<
"copied input file: "
input_file_name << endl
" to output file: "
output_file_name << endl;
return 0;
using namespace std;
int main (int argc, char * argv[]) {
if (argc != 3) {return 1;}
string input_file_name (argv[1]);
string output_file_name (argv[2]);
CSE 332: C++ Algorithms I
}
/* output:
cdgill@hive> ./copytest Makefile Makefile2
copied input file: Makefile
to output file: Makefile2
cdgill@hive> diff Makefile Makefile2
cdgill@hive>
*/
Example of Using Sorting Algorithms
• sort algorithm
– Reorders a given range
– Can also plug in a
functor to change the
ordering function
• next_permutation
algorithm
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main (int, char * []) {
– Generates a specific
kind of reordering,
called a “permutation”
– Can use to generate all
possible orders of a
given sequence
/* output is
original: asdf
sorted: adfs
permutations:
adsf afds afsd
dafs dasf dfas
dsfa fads fasd
fsad fsda sadf
sdfa sfad sfda
*/
asdf
dfsa
fdas
safd
adfs
string s = "asdf";
cout << "original: " << s << endl;
sort (s.begin(), s.end());
cout << "sorted: " << s << endl;
string t (s);
cout << "permutations:" << endl;
do {
next_permutation (s.begin(), s.end());
cout << s << " ";
} while (s != t);
asfd
dsaf
fdsa
sdaf
CSE 332: C++ Algorithms I
cout << endl;
return 0;
}
Example of Using Numeric Algorithms
• accumulate
algorithm
– Sums up elements in
a range (based on a
starting sum value)
• inner_product
algorithm
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
int main (int, char * []) {
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(2);
– Computes the inner
(also known as “dot”)
product of two
matrixes: sum of the
products of their
respective elements
/* output is:
v contains 1 2 3 2
the sum of the elements
in v is 8
the inner product of v
and itself is 18
*/
cout << "v contains ";
for (size_t s = 0; s < v.size(); ++s) {
cout << v[s] << " ";
}
cout << endl;
cout << "the sum of the elements in v is "
<< accumulate (v.begin(), v.end(), 0) << endl;
cout << "the inner product of v and itself is "
<< inner_product (v.begin(), v.end(),
v.begin(), 0) << endl;
return 0;
}
CSE 332: C++ Algorithms I
Concluding Remarks
• C++ libraries give you useful, generic algorithms
– Combine easily with a variety of containers/iterators
– Support many common data structure manipulations
• Finding and modifying values, re-ordering, numeric operations
– Reusing them saves you from writing code
• Many STL algorithms can be extended further
– Especially by plugging functors into them
– Next time we’ll look at how functors work, and how to use
them, as well as at algorithms and iterators in more detail
CSE 332: C++ Algorithms I
Download