Title: The STL
1The STL
- The heart of the STL is a collection of
algorithms and data structures - Each algorithm works with a large number of data
structures - If you create a new data structure it will work
with the algorithms - If you create a new algorithm is will work with
the data structures - It introduces some new concepts to allow this
2Interface
- How do the algorithms use the data structures?
- The data structures provide a consistent way of
access - We call them Iterators
3Designing the Interface
- An interface which is as generic as possible is
wanted - It should work with arrays - since they are
probably the simplest container - It should work with linked lists
- It should work with trees and hash tables
4Iterating through an array
- for (int index0indexltlengthindex)
- // do something with arrayindex
- for (T ptr array ptr!arraylengthptr)
- //do something with ptr
5Iterating through a linked list
- for (Node nodelist.head
- node!0nodenode-gtnext)
- // do something with node-gtvalue
6Generic Iterating
- Set current element to first element
- If current element is not past the end
- Do something with the current element
- Set current element to the next element
7STL Iterators
- The key to the STL is understanding that it is
designed to work with arrays - Arrays are built in to the language
- You cant inherit from them - so using OO
inheritance to write generic algorithms wont
work - You cant change the way arrays work - so you
need to be compatible with them
8The Basic Pointer Operations
- ptr - used to access what is pointed to
- ptr, ptr - used to advance to the next
element - ptr ptr2, ptr ! ptr2 - used to check if two
pointers point to the same element
9The STL Find Algorithm
- template lttypename Iterator, typename Tgt
- Iterator find(Iterator first,
- Iterator last, const T value) while
(first!last first ! value) first - return first
-
- Note that the following will work
- int array5 1,2,3,4,5
- cout ltlt (find(array,array5,3)) //not safe!
10Requirement, Concepts, Models
- A concept is a set of requirements
- A requirement is some operation doing a useful
thing - A model, is something that fulfills a concept.
- An Iterator is a concept
- A pointer is a model of an Iterator.
11Basic Concepts
- The fundamental concepts, that seem too obvious
to state - Assignable
- Possible to copy values
- Possible to assign new values
- Default Constructable
- Possible to construct an object with no arguments
- T() creates an object
- T t declares a variable
12Basic Concepts Continued
- Equality Comparable
- Possible to compare two object for equality
- x y and x ! y must do so
- LessThan Comparable
- Possible to test if one object is less than or
greater than another - xlty ,xgty, xlty, xgty must do so
- A regular type models all the above in a
consistent fashion
13Input Iterator
- The simplest Iterator
- Three kinds of values dereferencable, past the
end, and singular - Possible to compare for equality
- Possible to copy and assign
- Possible to dereference to get associated value
type - Possible to increment with i and i
14Input Iterators
- That is all, for example, the following do not
have to be possible - Modify the dereferenced value
- Other comparison operators
- Read a value more than once
15Output Iterators
- The other simple Iterator
- Possible to copy and assign
- Possible to write a value with i x
- Possible to increment
- (Again, writing twice isnt required, testing for
equality isnt required, etc)
16Using Iterators Example
- template lttypename InputIterator,
- typename OutputIteratorgt
- OutputIterator copy(
- InputIterator first,
- InputIterator last,
- OutputIterator result)
- for (first!lastresult,first)
- result first
- return result
-
17Iterator Implementation Example
- template lttypename Tgt
- class ostream_iterator
- public
- ostream_iterator(ostream s,const char c0)
- os(s),string( c )
- ostream_iterator(const ostream_iterator o)
- os(i.os), string(i.string)
- ostream_iterator operator(const
- ostream_iterator o)
- os i.os
- string i.string
- return this
-
-
18ostream_iteratorltTgt operator(const T value)
os ltlt value if (string) os ltlt
string return this ostream_iteratorltTgt
operator() return this ostream_iteratorltTgt
operator() return this ostream_iterator
ltTgt operator(int) return this private
ostream os const char string
19Forward Iterators
- Both an InputIterator and an OutputIterator
- Allows multi-pass algoithms
- pq q p x works
20Bidirectional Iterators
- Does everything a ForwardIterator does.
- Also supports decrement
- template lttypename BidirectionalIterator,
- typename OutputIterator gt
- OutputIterator reverse_copy( BidirectionalIterator
first, BidirectionalIterator last, - OutputIterator result)
- while (first ! last)
- (result) (--last)
- return result
-
21Random Access Iterators
- Supports everything that a Bidirectional
Iterators does - Supports random access
- Addition and subtraction i n and i - n
- Subscripting in
- Subtraction of iterators i1 - i2
- Ordering i1 lt i2
- Random access must be in constant time
- Basically acts just like a real pointer
22Ranges
- Iterators are often used in ranges
- A range is a start and end iterator
- The start iterator is part of the range
- The end iterator is not
- In maths its start, end)
- The empty range is startend
23Containers
- Containers contain elements
- Container - accessed via Input Iterators
- begin() and end() get iterators
- Forward Container - accessed via Forward
Iterators - Reversible Container - accessed via Bidirectional
Iterators - rbegin() and rend() get reverse iterators
- Random Access Containers - accessed via Random
Access Iterators
24More Container Types
- There are some other Container types
- Sequence
- Refinement of Forward Container
- Can add or delete elements at any point
- member functions insert and erase
- Associative Containers
- Every element has a key, by which it is looked up
- Elements are added and deleted via keys
25Sequence Abstractions
- Front Insertion Sequence
- Insertion at front in constant time
- Access first element in constant time
- Back Insertion Sequence
- Append to end in constant time
- Access last element in constant time
26Associative Container Abstractions
- Unique Associative Container
- No two elements have the same key
- Conditional insertion
- Multiple Associative Container
- May contain multiple elements with the same key
- Simple Associative Container
- The elements are their own keys
- Pair Associative Container
- Associates a key with another object
- The value type is pairltconst key, valuegt
27Associative Container Abstractions Continued
- Sorted Associative Container
- Sorts elements by key in a strict weak ordering
- Hashed Associative Container
- Uses a hash table implementation
28Vector
- Simplest container, often the most efficient
- Has both a size and a capacity
- Inserting elements can cause reallocation
- Reallocation invalidates iterators
- Random Access Container
- Back Insertion Sequence
29Vector Usage Example
- include ltiostreamgt
- include ltvectorgt
- include ltalgorithmgt
- include ltstringgt
- int main()
- vectorltstringgt v
- string s
- while(cingtgts)
- v.push_back(s)
- copy(v.begin(),v.end(),
- ostream_iteratorltstringgt(cout,"\n"))
-
30List
- A doubly linked list
- Insertion and spliciing do not invalidate
iterators - Deletion only invalidates iterators at the
deleted element - Reversible Container
- Front Insertion Sequence
- Back Insertion Sequence
31List Usage Example
- include ltiostreamgt
- include ltlistgt
- include ltalgorithmgt
- include ltstringgt
- int main()
- listltstringgt l
- string s
- while(cingtgts)
- l.push_front(s)
- copy(l.begin(), l.end(),
- ostream_iteratorltstringgt(cout,"\n"))
32Deque
- A double-ended queue
- Insertion invalidates all iterators
- Deletion from middle invalidates all iterators
- Deletion at the ends invalidates iterators at the
deleted element only - Random Access Container
- Front Insertion Sequence
- Back Insertion Sequence
33Deque Usage Example
- include ltiostreamgt
- include ltdequegt
- include ltalgorithmgt
- include ltstringgt
- int main()
- dequeltstringgt d
- d.push_back("first")
- d.push_front("second")
- d.insert(d.begin()1, "third")
- d2 "fourth"
- copy(d.begin(), d.end(),
- ostream_iteratorltstringgt(cout,"\n"))
-
34Set
- Maintains elements in sorted order
- Inserting does not invalidate iterators
- Deleting only invalidates iterators at the
deleted element - Sorted Associative Container
- Simple Associative Container
- Unique Associative Container
35- include ltiostreamgt
- include ltsetgt
- include ltalgorithmgt
- include ltstringgt
- int main()
- int prime_a5 2,3,5,7,11
- int odd_a5 1,3,5,7,9
- int even_a5 2,4,6,8,10
- setltintgt prime(prime_a,prime_a5)
- setltintgt odd(odd_a,odd_a5)
- setltintgt even(even_a,even_a5)
- cout ltlt "Union "
- set_union(prime.begin(), prime.end(),
- even.begin(), even.end(),
- ostream_iteratorltintgt(cout, " "))
36Multiset
- Inserting does not invalidate iterators
- Deleteing only invalidates iterators at the
deleted element - Sorted Associative Container
- Simple Associative Container
- Multiple Associative Container
37Map
- Inserting does not invalidate iterators
- Deleting only invalidates iterators at the
deleted element - Sorted Associative Container
- Pair Associative Container
- Unique Associative Container
38Map Usage Example
- include ltiostreamgt
- include ltmapgt
- include ltstringgt
- int main()
-
- mapltstring,intgt days
- days"January" 31
- days"February" 28
- days"March" 31
- days"April" 30
- cout ltlt"March "ltltdays"March"
- ltltendl
39Multimap
- Sorted Associative Container
- Pair Associative Container
- Multiple Associative Container
- Insertion does not invalidate iterators
- Deletion only invalidates iterators at the
deleted element
40Adapters
- Adapters are wrappers around a container
- They work with multiple containers
- They provide more specific interfaces
41Stack
- LIFO
- Can only insert, retrieve, and delete top element
- Can use any Front Insertion or Back Insertion
Container - By default a deque is used
- top() returns the top element
- push() inserts at the top
- pop() removes the top element
42Queue
- FIFO
- Elements are added to the back, and removed from
the front - Can use any Front and Back Insertion Sequence
- By default a deque is used
- front() retrieves element at the front
- push() adds element to the back
- pop() delete element at the front
43Priority_queue
- Can only retrieve and delete top element
- The top element is always the largest
- Can use any RandomAccessContainer
- By default uses a vector
- top() retrieves the top element
- push() inserts an element
- pop() removes the top element
44Function Objects
- It is often useful to supply a function to an
algorithm - It makes the algorithm more generic
- Sorting is the obvious example
- In the STL we don't actually pass a function
- A function object is used (which could in fact be
a function)
45What is a function object?
- The simplest function object is a function
pointer - However, an object can also be used
- If operator() is overloaded the object can be
used as a function - Using an object is more flexible
- An object can maintain state
46Types of function objects
- Generators
- Called with no arguments
- Unary Functions
- Called with one argument
- Unary Predicate
- A Unary Function that returns a boolean
- Binary Functions
- Called with two arguments
- Binary Predicate
- A Binary Function that returns a boolean
47Basic Function Objects
- Strict Weak Ordering
- A Binary Predicate
- f(x,x) is false
- f(x,y) implies !f(y,x)
- f(x,y) and f(y,z) implies f(x,z)
- f(x,y) false and f(y,x) false implies x and y are
equivalent - x and y equivalent, and y and z equivalent
implies x and z equivalent
48Basic Function Objects II
- Random Number Generator
- A Unary Function
- f(N) returns an integer in the range 0,N)
- Every integer in 0,N) will appear an equal
number of times - Hash Function
- A Unary Function
- Maps an object to a size_t
- Used by Hashed Associative Containers
49STL Provided Function Objects
- The STL provides a large number of Function
Objects - plus, minus, multiplies, etc
- logical_or,logical_and, etc
- less, greater, etc
50Find
- Performs a linear search
- include ltiostreamgt
- include ltstringgt
- include ltlistgt
- include ltalgorithmgt
- int main()
- listltstringgt l
- l.push_back("bob")
- l.push_back("john")
- l.push_back("kate")
- listltstringgtiterator it
- find(l.begin(),l.end(),"john")
- if (itl.end())
- cout ltlt John not found
- else
- cout ltlt John found
-
51Find_if
- Finds the first element which satisfies a
Predicate - include ltiostreamgt
- include ltstringgt
- include ltlistgt
- include ltalgorithmgt
- include ltfunctionalgt
- include ltcstdlibgt
- int main()
- listltintgt l
- for (int i0ilt10i)
- l.push_back(rand()100)
- cout ltlt find_if(l.begin(),l.end(),
- bind1st(lessltintgt(),50))
-
52Adjacent_find
- Performs a linear search thorugh a range of input
iterators - Searches for two adjacent elements
- If no binary predicate is supplied finds adjacent
equal elements - int main()
- int array5 1,2,3,4,1
- const int p adjacent_find(array,
- array5, greaterltintgt())
- if (p!array5)
- cout ltlt p ltlt " is wrong\n"
-
53Find_first_of
- Finds first occurance of a number of values
- Can be passed a comparison function object to use
- int main()
- string sentence here is a string."
- string vowels "aeiou"
- stringiterator it
- find_first_of(sentence.begin(),
- sentence.end(), vowels.begin(),
- vowels.end())
- cout ltlt it
-
54Search
- Similar to find and find_if
- Finds subranges instead of single elements
- int main()
- char sentence "this is a sentence"
- char word "is"
- char r search(sentence,
- sentencestrlen(sentence),
- word, wordstrlen(word))
- cout ltlt "Found " ltlt word ltlt " at
- ltlt r-sentence ltlt endl
-
55Find_end
- Should be called search_end
- Same as search, except returns the last subrange
that matches - int main()
- char sentence "this is a sentence"
- char word "is"
- char r find_end(sentence,
- sentencestrlen(sentence),
- word, wordstrlen(word))
- cout ltlt "Found " ltlt word ltlt " at
- ltlt r-sentence ltlt endl
-
56Search_n
- Searches for a subsequence of n consequitive
equal elements - Can be passed a Binary Predicate with which to
determine equality - int main()
- int A 1,1,2,3,1,1,1,2,3,1,1,1,1,2,3
- int N sizeof(A) / sizeof(A0)
- int r search_n(A,AN,4,1)
- cout ltlt "Sequence of 4 1's at element
- ltlt r-A ltlt endl
-
57Count
- Counts the elements that are equal to a value
- There is also a count_if which uses a Predicate
- int main()
- int A 1,2,3,1,2,3,1,2,3,1,2,1,1,2,3
- int N sizeof(A)/sizeof(A0)
- cout ltlt "Number of 2's
- ltlt count(A,AN,2) ltlt endl
-
58For_each
- Applies a Unary Function to each element of the
range - Returns the Unary Function
- struct sum
- int sum
- sum() sum(0)
- void operator()(int i) sumi
-
- int main()
- int A 1,2,3,1,2,3,1,2,3,1,2,1,1,2,3
- int N sizeof(A) / sizeof(A0)
- sum s for_each(A,AN,sum())
- cout ltlt s.sum ltlt endl
-
59Equal
- Compares two ranges
- Can use a BinaryPredicate for comparisons
- bool compare_nocase(char c1, char c2)
- return toupper(c1) toupper(c2)
-
- int main()
- const char s1 "a string"
- const char s2 "A string"
- if(equal(s1,s1strlen(s1),s2,compare_nocase))
- cout ltlt "Strings are equal" ltlt endl
-
60Mismatch
- Returns the first position that two ranges differ
- Returns a pair holding two iterators
- Can use a BinaryPredicate for comparisons
- int main()
- const char s1 "a string"
- const char s2 "A string"
- const char s1e s1strlen(s1)
- const char s2e s2strlen(s2)
- pairltconst char,const chargt p
- mismatch(s1,s1e,s2,compare_nocase)
- if (p.first s1e p.second s2e)
- cout ltlt "Strings are equal" ltlt endl
-
61Lexicographic_compare
- Returns true if first range is lexicographically
less than second - Can use a BinaryPredicate for comparisons
- int main()
- const char s1 "a string"
- const char s2 "A string"
- const int N1 strlen(s1)
- const int N2 strlen(s2)
- if (lexicographic_compare(s1,s1N1,s2,
- s2N2,compare_nocase))
- cout ltlt "s1 less than s2" ltlt endl
-
62min_element and max_element
- Returns an iterator at the smallest/largest
element of a range - Can use a BinaryPredicate for comparisons
- int main()
- listltintgt l
- generate_n(front_inserter(l),1000,rand)
- listltintgtconst_iterator min
- min_element(l.begin(),l.end())
- listltintgtconst_iterator max
- max_element(l.begin(),l.end())
- cout ltlt min ltlt " - " ltlt max ltlt endl
-
63Adapters
- Adapters transform one interface into another
- The STL provides function object adapters
- In fact it provides a lot of them
- We'll look at some of the most useful
64Binder1st
- Transforms a Binary Function into a Unary
Function - It binds the first argument to a constant
- To use it a helper function bind1st is provided
- int main()
- vectorltintgt v
- for (int i0ilt10i) v.push_back(i)
- vectorltintgtiterator vi
- find_if(v.begin(), v.end(),
- bind1st(lessltintgt(),5))
-
65Binder2nd
- Just like binder1st
- Binds the second argument to a constant
- int main()
- vectorltintgt v
- for (int i0ilt10i) v.push_back(i)
- vectorltintgtiterator vi
- find_if(v.begin(), v.end(),
- bind2nd(lessltintgt(),5))
66Unary_negate and Binary_negate
- unary_negate Negates a Unary Predicate
- Easiest to use with the not1 helper function
- binary_negate Negates a Binary Predicate
- Easiest to use with the not2 helper function
67Unary_compose and Binary_compose
- unary_compose creates composition of two Unary
Functions - Best to use the compose1 helper function
- compose1(f,g)(x) is the same as f(g(x))
- binary_compose creates composition of three
Functions - Best to use the compose2 helper function
- compose2(f,g1,g2)(x1,x2) is the same as
f(g1(x1),g1(x2))
68(No Transcript)