Noeud:Set, Noeud « Next »:, Noeud « Previous »:List, Noeud « Up »:Containers and Iterators



Set

Sets enable you to declare store data collections as individual items, although no duplicate elements are allowed (all elements must be unique). Unlike our previous examples of sequence containers (vector, deque and list), we can retrieve elements from a set (as we can from all sorted associative containers) rapidly - in logaritmic time - in comparisson with sequence containers, which are much slower. You use a set in your code by including <set>.

Inserting elements into a set is a little different to normal; a pair object is returned from an insertion, the first parameter being an iterator and the second being a boolean value, which determines if there were any duplicates or not. If there were, then the element is not inserted (only unique elements are allowed). Here's a simple example:

     /* set1.cc
        Compiled using g++ set1.cc Address.cc -o set1 */
     #include <set>
     #include "AddressRepository.hh"
     
     int main()
     {
       set<Address> set1;
       if (!set1.insert(addr1).second)
             cout << "Failed to insert addr1" << endl;
       if (!set1.insert(addr2).second)
             cout << "Failed to insert addr2" << endl;
       if (!set1.insert(addr3).second)
             cout << "Failed to insert addr3 " << endl;
       if (!set1.insert(addr4).second)
             cout << "Failed to insert addr4 " << endl;
     
       std::multiset<Address>::iterator pos;
       cout << "set1 now contains: " << endl;
       for (pos=set1.begin(); pos!=set1.end(); ++pos)
         {
           pos->print();
         }
       exit(0);
     }
     
     Example 3.11: set1.cc
     

The program produces the following output:

     $ ./set1
     Failed to insert addr4
     set1 now contains:
     Name: Adam, Street: 23 Big St., City: Worcs, Phone: 443098
     Name: Edith, Street: 91 Glib Terrace, City: Shrops, Phone: 858976
     Name: Jane, Street: 12 Small St., City: Worcs, Phone: 225343
     

Notice that elements are printed ascending alphabetically. This is because the default sorting criterion for a set uses < (Some Predefined Function Objects discusses how to change this ordering). Obviously, the Address object with the name Jane is not inserted. It's not because addr1 and addr4 have identical values such as street address, phone number etc.; this is incidental. Recall from Preliminaries that we defined a < operator for class Address, which tests only for names. Thus, when addr4 is about to be inserted, the insert operation finds that "Jane" already exists within the set and as a consequence addr4 is not inserted. The pair objects values can be accessed using the member variables first and second. As mentioned previously, when used with insert, first returns the iterator from the inserted element, and second returns whether the element was inserted or not.

Like list, set provides a number of searching methods that enable you to perform logarithmic-time complexity operations. This is in preference to the linear-time complexity of the searching algorithms provided by generic algorithms (see Generic Algorithms and Function Objects).

We'll only use a few searching methods with set; the others are easier used with multiset.

     /* set2.cc
        Compiled using g++ set2.cc Address.cc -o set2 */
     #include <set>
     #include "AddressRepository.hh"
     
     int main()
     {
       set<Address> set2;
       set2.insert(addr1);
       set2.insert(addr2);
       set2.insert(addr3);
       set2.insert(addr4);
       set2.insert(addr5);
     
       std::set<Address>::iterator pos;
       cout << "Found " << set2.count(addr4) << " elements with name \""
            << addr4.getName() << "\"" << endl;
       pos = set2.find(addr4);
       if (pos != set2.end())
         {
           cout << "Found: ";
           pos->print();
         }
       else
         {
           cout << "Could not find ";
           pos->print();
         }
        exit(0);
     }
     
     Example 3.12: set2.cc
     

Notice to start with that count takes an element of the set as an argument; it looks through the set and counts how many occurrences there are of that element. So set2.count(addr4) returns how many occurrences of addr4 there are in set2. Obviously in our case we'll only find one, because sets do not allow duplicates. Finding the element addr4 is easy, and can be achieved in logarithmic time using find. Although trivial for this example, it is extremely useful for much larger collections of objects to be able to make searches so quickly. find takes an element as an argument and returns an iterator to it. So in the section of code

       pos = set2.find(addr4);
       Address addr;
       if (pos != set2.end())
         {
           cout << "Found: ";
           pos->print();
         }
     

we first use an iterator to be assigned the location of the result of the find method (a failure returns end()) in the call pos = set2.find(addr4), and then if pos isn't equal to set2.end(), we print out the result of the find.

Here's the output:

     $ ./set2
     Found 1 element with name Jane
     Found: Name: Jane, Street: 12 Small St., City: Worcs, Phone: 225343