808 Standard Template Library Self-Test Exercises Tip Pitfall I TERATORS AND R EMOVING E LEMENTS Adding or removing an element to or from a container can affect other iterators. In general, there is no guarantee that the iterators will be located at the same element after an addition or deletion. Some containers do, however, guarantee that the iterators will not be moved by additions or deletions, except of course if the iterator is located at an element that is removed. Of the template classes we have seen so far, list and slist guarantee that their iterators will not be moved by additions or deletions, except of course if the iterator is located at an element that is removed. The template classes vector and deque make no such guarantee. T YPE D EFINITIONS IN C ONTAINERS The STL container classes contain type definitions that can be handy when programming with these classes. We have already seen that STL container classes may contain the type names iterator, const_iterator, reverse_iterator, and const_reverse_iterator (and hence must contain their type definitions behind the scene). There are typically other type definitions as well. The type value_type is the type of the elements stored in the container, and size_type is an unsigned integer type that is the return type for the member function size. For example, list<int>::value_type is another name for int. All the template classes we have discussed so far have the defined types value_type and size_type. 7. What is a major difference between vector and list? 8. Which of the template classes slist, list, vector, and deque have the member function push_back? 9. Which of the template classes slist, list, vector, and deque have random-access iterators? 10. Which of the template classes slist, list, vector, and deque can have mutable iterators? S EQUENTIAL C ONTAINERS A sequential container arranges its data items into a list so that there is a first element, a next ele- ment, and so forth, up to a last element. The sequential container template classes that we have discussed are slist, list, vector, and deque. 19_CH19.fm Page 808 Monday, August 18, 2003 2:11 PM Containers 809 Self-Test Exercises ■ THE CONTAINER ADAPTERS stack AND queue Container adapters are template classes that are implemented on top of other classes. For example, the stack template class is by default implemented on top of the deque template class, which means that buried in the implementation of the stack is a deque where all the data resides. However, you are shielded from this implementation detail and see a stack as a simple last-in/first-out data structure. Other container adapter classes are the queue and priority_queue template classes. Stacks and queues were discussed in Chapter 17. A priority queue is a queue with the additional property that each entry is given a priority when it is added to the queue. If all entries have the same priority, then entries are removed from a priority queue in the same manner as they are removed from a queue. If items have different priorities, the higher-priority items are removed before lower-priority items. We will not discuss prior- ity queues in any detail, but mention it for those who may be familiar with the concept. Although an adapter template class has a default container class on top of which it is built, you may choose to specify a different underlying container, for efficiency or other reasons, depending on your application. For example, any sequence container may serve as the underlying container for the stack template class, and any sequence con- tainer other than vector may serve as the underlying container for the queue template class. The default underlying data structure is the deque for both the stack and the queue. For a priority_queue the default underlying container is a vector. If you are happy with the default underlying container type, then a container adapter looks like any other template container class to you. For example, the type name for the stack template class using the default underlying container is stack<int> for a stack of ints. If you wish to specify that the underlying container is instead the vector template class, you would use stack<int, vector<int> > as the type name. We will always use the default underlying container. If you do specify an underlying container, be warned that you should not place two > symbols in the type expression without a space in between them, or the compiler can be confused. Use stack<int, vector<int> >, with a space between the last two >’s. Do not use stack<int, vector<int>>. The member functions and other details about the stack template class are given in Display 19.8. For the queue template class these details are given in Display 19.9. A simple example of using the stack template class is given in Display 19.10. 11. What kind of iterators (forward, bidirectional, or random-access) does the stack template adapter class have? 12. What kind of iterators (forward, bidirectional, or random-access) does the queue template adapter class have? 13. If s is a stack<char>, what is the type of the returned value of s.pop( )? priority queue Warning! 19_CH19.fm Page 809 Monday, August 18, 2003 2:11 PM 810 Standard Template Library ■ THE ASSOCIATIVE CONTAINERS set AND map Associative containers are basically very simple databases. They store data, such as structs or any other type of data. Each data item has an associated value known as its key. For example, if the data is a struct with an employee’s record, the key might be the employee’s Social Security number. Items are retrieved on the basis of the key. The key type and the type for data to be stored need not have any relationship to one another, although they often are related. A very simple case is when each data item is its own key. For example, in a set every element is its own key. The set template class is, in some sense, the simplest container you can imagine. It stores elements without repetition. The first insertion places an element in the set. Additional insertions after the first have no effect, so that no element appears more than once. Each element is its own key. Basically, you just add or delete elements and ask if an element is in the set or not. Like all STL classes, the set template class was Display 19.8 The stack Template Class stack A DAPTER T EMPLATE C LASS D ETAILS Type name : stack<T> or stack<T, Sequence_Type > for a stack of elements of type T. Library header : <stack>, which places the definition in the std namespace. Defined types : value_type, size_type. There are no iterators. S AMPLE M EMBER F UNCTIONS MEMBER FUNCTION (s IS A STACK OBJECT) MEANING s.size( ) Returns the number of elements in the stack. s.empty( ) Returns true if the stack is empty; otherwise, returns false. s.top( ) Returns a mutable reference to the top member of the stack. s.push( Element ) Inserts a copy of Element at the top of the stack. s.pop( ) Removes the top element of the stack. Note that pop is a void func- tion. It does not return the element removed. s1 == s2 True if s1.size( ) == s2.size( ) and each element of s1 is equal to the corresponding element of s2; otherwise, returns false. The stack template class also has a default constructor, a copy constructor, and a constructor that takes an object of any sequence class and initializes the stack to the elements in the sequence. It also has a destructor that returns all storage for recycling, and a well-behaved assignment operator. key set 19_CH19.fm Page 810 Monday, August 18, 2003 2:11 PM Containers 811 Display 19.9 The queue Template Class queue A DAPTER T EMPLATE C LASS D ETAILS Type name : queue<T> or queue< Sequence_Type , T> for a queue of elements of type T. For efficiency reasons, the Sequence_Type cannot be a vector type. Library header : <queue>, which places the definition in the std namespace. Defined types : value_type, size_type. There are no iterators. S AMPLE M EMBER F UNCTIONS MEMBER FUNCTION (q IS A QUEUE OBJECT) MEANING q.size( ) Returns the number of elements in the queue. q.empty( ) Returns true if the queue is empty; otherwise, returns false. q.front( ) Returns a mutable reference to the front member of the queue. q.back( ) Returns a mutable reference to the last member of the queue. q.push( Element ) Adds Element to the back of the queue. q.pop( ) Removes the front element of the queue. Note that pop is a void function. It does not return the element removed. q1 == q2 True if q1.size( ) == q2.size( ) and each element of q1 is equal to the corresponding element of q2; otherwise, returns false. The queue template class also has a default constructor, a copy constructor, and a constructor that takes an object of any sequence class and initializes the stack to the elements in the sequence. It also has a destructor that returns all storage for recycling, and a well-behaved assignment operator. Display 19.10 Program Using the stack Template Class (part 1 of 2) 1 //Program to demonstrate use of the stack template class from the STL. 2 #include <iostream> 3 #include <stack> 4 using std::cin; 5 using std::cout; 6 using std::endl; 7 using std::stack; 8 int main( ) 9 { 19_CH19.fm Page 811 Monday, August 18, 2003 2:11 PM 812 Standard Template Library written with efficiency as a goal. To work efficiently, a set object stores its values in sorted order. You can specify the order used for storing elements as follows: set<T, Ordering > s; Ordering should be a well-behaved ordering relation that takes two arguments of type T and returns a bool value. 2 T is the type of elements stored. If no ordering is specified, 2 The ordering must be a strict weak ordering. Most typical ordering used to implement the < operator is strict weak ordering. For those who want the details: A strict weak ordering must be: (irreflexive) Ordering(x, x) is always false; (antisymmetric) Ordering(x, y) implies !Order- ing(y, x); (transitive) Ordering(x, y) and Ordering(y, z) implies Ordering(x, z); and (transitivity of equivalence) if x is equivalent to y and y is equivalent to z, then x is equivalent to z. Two ele- ments x and y are equivalent if Ordering(x, y) and Ordering(y, x) are both false. Display 19.10 Program Using the stack Template Class (part 2¬ of 2) 10 stack<char> s; 11 cout << "Enter a line of text:\n"; 12 char next; 13 cin.get(next); 14 while (next != ’\n’) 15 { 16 s.push(next); 17 cin.get(next); 18 } 19 cout << "Written backward that is:\n"; 20 while ( ! s.empty( ) ) 21 { 22 cout << s.top( ); 23 s.pop( ); 24 } 25 cout << endl; 26 return 0; 27 } S AMPLE D IALOGUE Enter a line of text: straw Written backward that is: warts The member function pop removes one element, but does not return that element. pop is a void function. Therefore, we needed to use top to read the element we removed. 19_CH19.fm Page 812 Monday, August 18, 2003 2:11 PM Containers 813 then the ordering is assumed to use the < relational operator. Some basic details about the set template class are given in Display 19.11. A simple example that shows how to use some of the member functions of the template class set is given in Display 19.12 . A map is essentially a function given as a set of ordered pairs. For each value first that appears in a pair, there is at most one value second such that the pair (first, second) is in the map. The template class map implements map objects in the STL. For example, if Display 19.11 The set Template Class set T EMPLATE C LASS D ETAILS Type name : set<T> or set<T, Ordering > for a set of elements of type T. The Ordering is used to sort elements for storage. If no Ordering is given, the ordering used is the binary operator, <. Library header : <set> which places the definition in the std namespace. Defined types include value_type, size_type. Iterators : iterator, const_iterator, reverse_iterator, and const_reverse_iterator. All iterators are bidirectional and those not including const_ are mutable. begin( ), end( ), rbegin( ), and rend( ) have the expected behavior. Adding or deleting elements does not affect iterators, except for an iterator located at the element removed. S AMPLE M EMBER F UNCTIONS MEMBER FUNCTION (s IS A SET OBJECT) MEANING s.insert( Element ) Inserts a copy of Element in the set. If Element is already in the set, this has no effect. s.erase( Element ) Removes Element from the set. If Element is not in the set, this has no effect. s.find( Element ) Returns a mutable iterator located at the copy of Element in the set. If Element is not in the set, s.end( ) is returned. s.erase( Iterator ) Erases the element at the location of the Iterator . s.size( ) Returns the number of elements in the set. s.empty( ) Returns true if the set is empty; otherwise, returns false. s1 == s2 Returns true if the sets contain the same elements; otherwise, returns false. The set template class also has a default constructor, a copy constructor, and other specialized construc- tors not mentioned here. It also has a destructor that returns all storage for recycling, and a well-behaved assignment operator. map 19_CH19.fm Page 813 Monday, August 18, 2003 2:11 PM 814 Standard Template Library Display 19.12 Program Using the set Template Class 1 //Program to demonstrate use of the set template class. 2 #include <iostream> 3 #include <set> 4 using std::cout; 5 using std::endl; 6 using std::set; 7 using std::set<char>::const_iterator; 8 int main( ) 9 { 10 set<char> s; 11 s.insert(’A’); 12 s.insert(’D’); 13 s.insert(’D’); 14 s.insert(’C’); 15 s.insert(’C’); 16 s.insert(’B’); 17 cout << "The set contains:\n"; 18 const_iterator p; 19 for (p = s.begin( ); p != s.end( ); p++) 20 cout << *p << " "; 21 cout << endl; 22 cout << "Removing C.\n"; 23 s.erase(’C’); 24 for (p = s.begin( ); p != s.end( ); p++) 25 cout << *p << " "; 26 cout << endl; 27 return 0; 28 } S AMPLE D IALOGUE The set contains: A B C D Removing C. A B D No matter how many times you add an element to a set, the set contains only one copy of that element. 19_CH19.fm Page 814 Monday, August 18, 2003 2:11 PM Containers 815 you want to assign a unique number to each string name, you could declare a map object as follows: map<string, int> numberMap; For string values known as keys, the numberMap object can associate a unique int value. Like a set object, a map object stores its elements in sorted order by its key values. You can specify the ordering on keys as a third entry in the angular brackets, < >. If you do not specify an ordering, a default ordering is used. The restrictions on orderings you can use are the same as those on the orderings allowed for the set template class. Note that the ordering is on key values only. The second type can be any type and need not have anything to do with any ordering. As with the set object, the sorting of the stored entries in a map object is done for reasons of efficiency. Some basic details about the map template class are given in Display 19.13. In order to understand these details, you need to first know something about the pair template class. The STL template class pair<T1, T2> has objects that are pairs of values such that the first element is of type T1 and the second is of type T2. If aPair is an object of type pair<T1, T2>, then aPair.first is the first element, which is of type T1, and aPair.sec- ond is the second element, which is of type T2. The member variables first and second are public member variables, so no accessor or mutator functions are needed. The header file for the pair template is <utility>. So, to use the pair template class, you need the following, or something like it, in your file: #include<utility> using std::pair; We will mention two other associative containers, although we will not give any details about them. The template classes multiset and multimap are essentially the same as set and map, respectively, except that multiset allows repetition of elements and multimap allows multiple values to be associated with each key value. ■ EFFICIENCY The STL was designed with efficiency as an important consideration. In fact, the STL implementations strive to be optimally efficient. For example, the set and map elements are stored in sorted order so that algorithms that search for the elements can be more efficient. Each of the member functions for each of the template classes has a guaranteed max- imum running time. These maximum running times are expressed using what is called big-O notation, which we discuss in Section 19.3. (Section 19.3 also gives some guar- anteed running times for some of the container member functions we have already dis- cussed. These are given in the subsection entitled “Container Access Running Times.”) When using more advanced references or even later in this chapter, you will be told the guaranteed maximum running times for certain functions. pair 19_CH19.fm Page 815 Monday, August 18, 2003 2:11 PM 816 Standard Template Library Display 19.13 The map Template Class map T EMPLATE C LASS D ETAILS Type name : map< KeyType , T> or map< KeyType , T, Ordering > for a map that associates (“maps”) ele- ments of type KeyType to elements of type T. The Ordering is used to sort elements by key value for effi- cient storage. If no Ordering is given, the ordering used is the binary operator, <. Library header : <map>, which places the definition in the std namespace. Defined types include key_type for the type of the key values, mapped_type for the type of the values mapped to, and size_type. (So, the defined type key_type is simply what we called KeyType above.) Iterators : iterator, const_iterator, reverse_iterator, and const_reverse_iterator. All iterators are bidirectional. Those iterators not including const_ are neither constant nor mutable but something in between. For example, if p is of type iterator, then you can change the key value but not the value of type T. Perhaps it is best, at least at first, to treat all iterators as if they were constant. begin( ), end( ), rbegin( ), and rend( ) have the expected behavior. Adding or deleting elements does not affect iterators, except for an iterator located at the element removed. S AMPLE M EMBER F UNCTIONS MEMBER FUNCTION (m IS A MAP OBJECT) MEANING m.insert( Element ) Inserts Element in the map. Element is of type pair< KeyType , T>. Returns a value of type pair<iterator, bool>. If the insertion is successful, the second part of the returned pair is true and the itera- tor is located at the inserted element. m.erase( Target_Key ) Removes the element with the key Target_Key . m.find( Target_Key ) Returns an iterator located at the element with key value Target_Key . Returns m.end( ) if there is no such element. m.size( ) Returns the number of pairs in the map. m.empty( ) Returns true if the map is empty; otherwise, returns false. m1 == m2 Returns true if the maps contain the same pairs; otherwise, returns false. The map template class also has a default constructor, a copy constructor, and other specialized construc- tors not mentioned here. It also has a destructor that returns all storage for recycling, and a well-behaved assignment operator. 19_CH19.fm Page 816 Monday, August 18, 2003 2:11 PM Generic Algorithms 817 Self-Test Exercises 14. Why are the elements in the set template class stored in sorted order? 15. Can a set have elements of a class type? 16. Suppose s is of the type set<char>. What value is returned by s.find(’A’) if ’A’ is in s? What value is returned if ’A’ is not in s? Generic Algorithms “And if you take one from three hundred and sixty-five, what remains?” “Three hundred and sixty-four, of course.” Humpty Dumpty looked doubtful. “I'd rather see that done on paper,” he said. Lewis Carroll, Through the Looking-Glass This section covers some basic function templates in the STL. We cannot give you a comprehensive description of them all here, but we will present a large enough sample to give you a good feel for what is contained in the STL and to give you sufficient detail to start using these template functions. These template functions are sometimes called generic algorithms. The term algo- rithm is used for a reason. Recall that an algorithm is just a set of instructions for perform- ing a task. An algorithm can be presented in any language, including a programming language like C++. But, when using the word algorithm, programmers typically have in mind a less formal presentation given in English or pseudocode. As such, it is often thought of as an abstraction of the code defining a function. It gives the important details but not the fine details of the coding. The STL specifies certain details about the algorithms underlying the STL template functions, which is why they are sometimes called generic algorithms. These STL function templates do more than just deliver a value in any way that the implementers wish. The function templates in the STL come with minimum requirements that must be satisfied by their implementations if they are to satisfy the standard. In most cases they must be implemented with a guaranteed run- ning time. This adds an entirely new dimension to the idea of a function interface. In the STL the interface not only tells a programmer what the function does and how to use the functions, but also how rapidly the task will be done. In some cases the stan- dard even specifies the particular algorithm that is used, although not the exact details of the coding. Moreover, when it does specify the particular algorithm, it does so because of the known efficiency of the algorithm. The key new point is the specifica- tion of an efficiency guarantee for the code. In this chapter we will use the terms generic algorithm, generic function, and STL function template to all mean the same thing. 19.3 generic algorithm 19_CH19.fm Page 817 Monday, August 18, 2003 2:11 PM . recycling, and a well-behaved assignment operator. key set 19_CH19.fm Page 810 Monday, August 18, 2003 2:11 PM Containers 811 Display 19.9 The queue Template Class queue A DAPTER T EMPLATE C LASS . std::cout; 6 using std::endl; 7 using std::stack; 8 int main( ) 9 { 19_CH19.fm Page 811 Monday, August 18, 2003 2:11 PM 812 Standard Template Library written with efficiency as a goal. To work efficiently,. Therefore, we needed to use top to read the element we removed. 19_CH19.fm Page 812 Monday, August 18, 2003 2:11 PM Containers 813 then the ordering is assumed to use the < relational operator. Some