cse 332: c++ stl algorithms c++ stl algorithms generic algorithms –apply to a wide range of types...

20
CSE 332: C++ STL algorithms C++ STL Algorithms • Generic algorithms – Apply to a wide range of types E.g., sorting integers (int) vs. intervals (pair<int, int>) – Don’t require inheritance relationships • Types substituted need not have a common base class • Need only to be models of the algorithm’s concept • Implementations in C++ – Rely on templates, interface-based polymorphism – Algorithms are implemented as function templates – Use types that model iterator concepts – Iterators in turn give access to containers

Upload: chrystal-marsh

Post on 26-Dec-2015

232 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

C++ STL Algorithms• Generic algorithms

– Apply to a wide range of types• E.g., sorting integers (int) vs. intervals (pair<int, int>)

– Don’t require inheritance relationships• Types substituted need not have a common base class• Need only to be models of the algorithm’s concept

• Implementations in C++– Rely on templates, interface-based polymorphism– Algorithms are implemented as function templates– Use types that model iterator concepts– Iterators in turn give access to containers

Page 2: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Example Revisited: Linear Search

• 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++

Page 3: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Review in Detail: Linear Search with Ranges

• First generalization (Austern, pp. 11): use a range

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?

Page 4: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

General Requirements for Linear Search

• Before we try to improve the algorithm further– Let’s come up with a definition of what it needs to do– This helps to plan what to require and what to leave flexible

• Any linear search implementation must offer a way to:– Indicate the sequence over which search will occur– Represent a position within the sequence– Advance to the next element of the sequence– Detect the end of the sequence– Return a value as an indication of success or failure

• Goal: meet these requirements flexibly and efficiently

Page 5: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

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 data structure whose ranges can’t be traversed via simple pointers?

Page 6: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Linear Search with Generic Iterators

• Third generalization: separate iterator type parameter• The STL’s linear search 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

Page 7: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Algorithm Concepts and Models

• Remember a concept gives a set of type requirements– Classify/categorize types (e.g., random access iterators)– Tells whether or not a type can or cannot be used with a

particular STL algorithm (get a compiler error if it cannot)• E.g., we couldn’t use a linked list iterator in find1 or even find2

• Any specific type that meets the requirements is a model of that concept– E.g., list<char>::iterator vs. char * in find

• Different abstractions (bi-linked list vs. array iterators)• No inheritance-based relationship between them • But both model iterator concept necessary for find

Page 8: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Concepts and Modeling Review, Continued• What very basic concept does the last statement in

STL find, (the line return first;) assume?– Asked another way, what must be able to happen to first

when it’s returned from function find? – Same requirement imposed by by-value iterator parameters

• What other capabilities are required of the Iterator and T type parameters by the STL find algorithm ?

template <typename Iterator, typename T>Iterator find (Iterator first, Iterator last,

const T & value) { while (first != last && *first != value) ++first; return first;}

Page 9: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Concepts and Modeling Review, Continued• What very basic concept does the last statement in

STL find, (the line return first;) assume?– Asked another way, what must be able to happen to first

when it’s returned from function find? – Same requirement imposed by by-value iterator parameters

• What other capabilities are required of the Iterator and T type parameters by the STL find algorithm ?

template <typename Iterator, typename T>Iterator find (Iterator first, Iterator last,

const T & value) { while (first != last && *first != value) ++first; return first;}

Page 10: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Matching an Algorithm to the Iterators it NeedsCategory/ Operation

Output Input Forward BidirectionalRandom

Access

Read =*p(r-value)

=*p(r-value)

=*p(r-value)

=*p(r-value)

Access -> -> ->->

[]

Write *p=(l-value)

*p=(l-value)

*p=(l-value)

*p=(l-value)

Iteration ++ ++ ++ ++ --++ -- + - += -=

Comparison == != == != == !=== != < > <= >=

What STL iterator category does find require?

Page 11: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

What if an Algorithm Has Alternative Versions?

• First approach: dynamic dispatch– Different names of

implementations– Run-time iterator

type test– Calls the best

implementation– What are the

limitations here?

// Based on Austern, pp. 38

template <class Iter, class Distance>

void move_fwd (Iter &i, Distance d) {

while (d>0) {--d; ++i} // O(d)

}

template <class Iter, class Distance>

void move_rand (Iter &i, Distance d) {

i+=d; // O(1)

}

template <class Iter, class Distance>

void move (Iter &i, Distance d) {

if (is_rand(i)) move_rand (i, d)

else if (is_fwd(i)) move_fwd (i, d)

// else ...

}

Page 12: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Iterator Traits and Category Type Tags• Need a few

concrete types to use as tags– E.g., empty structs– E.g., input, output, fwd, bidir, and rand

• Tags provide yet another associated type for iterators– Iterator category– Again, made

available by using the traits idiom

struct input {}; // empty structs for type tags

struct output {};

struct fwd : public input {}; // note inheritance

struct bidir : public fwd {};

struct rand : public bidir {};

template <typename I> struct iterator_traits {

...

typedef typename I::iterator_category

iterator_category;

};

template <typename T> struct iterator_traits<T*> {

...

typedef rand iterator_category;

};

template <typename T>

struct iterator_traits<const T*> {

...

typedef rand iterator_category;

};

(actually, random_access_iterator_tag)

Page 13: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Algorithm Dispatching via Category Tags• Static dispatching

– Implementations provide different signatures

– Iterator type is evaluated at compile-time

– Links to the best implementation

• Notice how type tags are used

// Based on Austern, pp. 38, 39

template <class Iter, class Distance>

void move (Iter i, Distance d, fwd) {

while (d>0) {--d; ++i;} // O(d)

}

template <class Iter, class Distance>

void move (Iter i, Distance d, rand) {

i += d; // O(1)

}

template <class Iter, class Distance>

void move (Iter i, Distance d) {

move (i, d,

iterator_traits<Iter>::

iterator_category()

)

}

concrete tag (empty struct) type

explicit constructor call

concrete tag (empty struct) type

Page 14: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Organization of Algorithms within the STL• 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

Page 15: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

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;

i = 2;

cout << i << " appears " << count(v.begin(), v.end(), i) << " times in v" << endl;

return 0;}

/* output is7 appears 0 times in v2 appears 2 times in v */

Page 16: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Using a Function Object to Extend an Algorithm • count_if algorithm

– Generalizes the count algorithm

– Instead of comparing for equality to a value

– Applies a given predicate function object (functor)

– If functor’s result is true, increases count

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

template <typename T>struct odd { bool operator() (T t) const { return (t % 2) != 0; }};

int main (int, char * []) {

vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(2);

cout << "there are " << count_if(v.begin(), v.end(), odd<int>()) << " odd numbers in v" << endl;

return 0;}

/* output isthere are 2 odd numbers in v */

Page 17: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Example of Using Mutating Algorithms• copy algorithm

– 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)

ifstream input_file (input_file_name.c_str());

ofstream output_file (output_file_name.c_str());

input_file >> noskipws; istream_iterator<char> i (input_file); ostream_iterator<char> o (output_file);

copy (i, istream_iterator<char>(), o);

cout << "copied input file: " << input_file_name << endl << " to output file: " << output_file_name << endl;

return 0;}

/* output:cdgill@hive> ./copytest Makefile Makefile2copied input file: Makefile to output file: Makefile2cdgill@hive> diff Makefile Makefile2cdgill@hive> */

#include <iostream>

#include <string>

#include <fstream>

#include <iterator>

#include <algorithm>

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]);

Page 18: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

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– Generates a specific kind of

reordering, called a “permutation”

– Can use to generate all possible orders of a given sequence

#include <iostream>#include <string>#include <algorithm>

using namespace std;

int main (int, char * []) {

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);

cout << endl;

return 0;}

/* output isoriginal: asdfsorted: adfspermutations:adsf afds afsd asdf asfddafs dasf dfas dfsa dsaf dsfa fads fasd fdas fdsa fsad fsda sadf safd sdaf sdfa sfad sfda adfs */

Page 19: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Example of Using Numeric Algorithms• accumulate

algorithm– Sums up elements in

a range (based on a starting sum value)

• inner_product algorithm– Computes the inner

(also known as “dot”) product of two matrixes: sum of the products of their respective elements

#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);

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;}

/* output is:v contains 1 2 3 2 the sum of the elements in v is 8the inner product of v and itself is 18 */

Page 20: CSE 332: C++ STL algorithms C++ STL Algorithms Generic algorithms –Apply to a wide range of types E.g., sorting integers ( int ) vs. intervals ( pair )

CSE 332: C++ STL algorithms

Concluding Remarks• STL algorithms give you useful, generic functions

– 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– Especially by plugging functors into them– We’ve looked at how to use a few functors– Next lecture we’ll look at how functors work

• You can also create your own generic algorithms– If something you need is not in the STL– Think about the iterator and data type concept it requires– Implement a version that works as generically as possible– Use traits-based dispatching to support more specific (and

thus more efficient) versions