Associative Containers

Sets & Multisets

Maps & Multimaps

 

Sets and multisets

•      Must #include <set> to use

•      The class template that defines this container:
template <class T,
          class Compare = less<T>
          class Allocator = allocator<T> >
 class set;

•      The elements of the set or multiset must be assignable, copyable and comparable

•      By default, the function object less sorts the elements by comparing them with the < operator

•      In systems without support for default template parameters, the third is usually omitted, the second required

 

To be comparable

•      The sorting criterion must be “strict weak ordering”

–   Antisymmetric

•   If x < y is true, then y < x is false

•   If op(x,y) is true, then op(y,x) is false

–   Transitive

•   If x < y and y < z then x < z

–   Irreflexive

•   x < x is always false

 

Preconditions to understanding

•      Functors: a predefined functor less<T> is the default in the class template definition

–   Sorts the container in ascending order

–   This can be replaced by a different predefined functor

–   Or, you could write your own functor for a sorting criteria

•      Pairs: each element in maps and multimaps is a pair

 

Sets and Multisets

•      Implemented as balanced binary search trees (red-black trees)

•      To modify the value of an element, you must remove the old element and insert a new one

•      Global algorithms that remove elements or  that reorder or modify elements cannot be used with associative containers

–    Trying will result in a compiler error

–    This is because if the value or position of elements could be changed,  the collection would not be sorted anymore

–    If you want to remove elements from an associative container, you must use the member functions

 

Advantages and disadvantages of associate containers

•      Advantage

–   Efficient; O(log n) search time

•      Disadvantages

–   Constraints:

•   Cannot change the value of an element directly

–   Might screw up ordering

–   So, to modify the value of an element, you must remove it and insert a new one

 

Special search member functions

count (elem) —returns the number of element with value elem

find (elem) —returns an iterator where the first occurrence of elem is found

Only for multisets

lower_bound (elem) —returns an iterator for the first element that has the same or greater value than elem

upper_bound (elem) —returns an iterator for the first element that has a greater value than elem

equal_range(elem) —returns a pair, the first and last position where elem would get inserted

 

Insert and remove operations

•      Sets

–  insert(elem) —returns pair<iterator, bool>

–  insert(pos, elem) —returns iterator

•   pos is a hint pointing to where the insert should start

•      Multiset

–  insert(elem) —returns an iterator

–  insert(pos, elem) —returns an iterator

•      The elem argument is always constant

•      The iterator argument is a hint of where to begin searching for the position to insert

 

Maps and Multimaps

•    template < class Key, class T,
          class Compare = less<T>

•    class Allocator = allocator<pair<const Key,T> >
 class map;

•      Sets, multisets, maps and multimaps usually use the same internal data type

•      You could consider set as special maps for which the value and key of the elements are the same object

•      The key of the elements inside a map is constant, but the value is not

•      The type of the elements stored in the map or multimap must be pair
<const Key, T>

 

The pair class

•      This utility is used when you want to treat two values as a single unit

–   It is used with map and multimap

–   Also used when you have a function that you want to return two values.

•      The template class pair, which can hold a pair of values, is defined in <utility>

 

The pair class template

•     template<class T1, classT2>
struct pair
{
   typedef T1 first_type;
   typedef T2 second_type;

   T1 first;  
//data members
  T2 second;

   pair();  
//constructors
   pair(const T1& key, const T2& value)
}

•      Example of use:
          
pair<int, string>(34, “Hi”)

 

Function make_pair()

•      This enables your to create a value pair without writing the types explicitly.

–   Unqualified floating literals have type double

•   make_pair takes two objects as arguments, and returns an object of type pair

•      Example:  make_pair(56, 3.14159)

Searching

•      Maps sort their elements automatically according to the element’s keys

•      Searching for elements with certain keys have good performance but

–   Searching for elements with certain value have bad performance.

 

Search operations

•      If you want to search for a value, not a key then you can’t use member function find( )

•      You can use the general algorithm find_if( ) or program it yourself as follows

Multimap<string, float>::iterator pos;

For (pos = coll.begin();
   pos != coll.end(); ++pos)

{   if (pos->second == value)

   {do_something( ); }

     }

•      The iterator is pointing to a pair, not a single item

•      What is the time complexity of searching for a value as opposed to searching for a key?

 

Access to elements

•      The usual way to access elements in a map is via iterators, like sets and multisets

–    But maps enable you to insert elements by using the subscript operator[ ]

•      So, maps can also be used as an associative array

–    The index is used as the key, and may have any type, not just an integer

–    You cannot have a wrong index with an associative array

•    If you use a key as an index, and that does not exist, it will be created and inserted into the map

•      You can’t use the subscript operator for multimaps

**************************************************************************

/* The following code example is taken from the book

 * "The C++ Standard Library - A Tutorial and Reference"

 * by Nicolai M. Josuttis, Addison-Wesley, 1999

 *

 * (C) Copyright Nicolai M. Josuttis 1999.

 * Permission to copy, use, modify, sell and distribute this software

 * is granted provided this copyright notice appears in all copies.

 * This software is provided "as is" without express or implied

 * warranty, and with no claim as to its suitability for any purpose.

 */

#include <iostream>

#include <map>

#include <string>

using namespace std;

 

int main()

{

    /* create map / associative array

     * - keys are strings

     * - values are floats

     */

    typedef map<string,float> StringFloatMap;

 

    StringFloatMap stocks;      // create empty container

 

    // insert some elements

    stocks["BASF"] = 369.50;

    stocks["VW"] = 413.50;

    stocks["Daimler"] = 819.00;

    stocks["BMW"] = 834.00;

    stocks["Siemens"] = 842.20;

 

    // print all elements

    StringFloatMap::iterator pos;

    for (pos = stocks.begin(); pos != stocks.end(); ++pos) {

        cout << "stock: " << pos->first << "\t"

             << "price: " << pos->second << endl;

    }

    cout << endl;

 

    // boom (all prices doubled)

    for (pos = stocks.begin(); pos != stocks.end(); ++pos) {

        pos->second *= 2;

    }

 

    // print all elements

    for (pos = stocks.begin(); pos != stocks.end(); ++pos) {

        cout << "stock: " << pos->first << "\t"

             << "price: " << pos->second << endl;

    }

    cout << endl;

 

    /* rename key from "VW" to "Volkswagen"

     * - only provided by exchanging element

     */

    stocks["Volkswagen"] = stocks["VW"];

    stocks.erase("VW");

 

    // print all elements

    for (pos = stocks.begin(); pos != stocks.end(); ++pos) {

        cout << "stock: " << pos->first << "\t"

             << "price: " << pos->second << endl;

    }

}

 

/* The following code example is taken from the book

 * "The C++ Standard Library - A Tutorial and Reference"

 * by Nicolai M. Josuttis, Addison-Wesley, 1999

 *

 * (C) Copyright Nicolai M. Josuttis 1999.

 * Permission to copy, use, modify, sell and distribute this software

 * is granted provided this copyright notice appears in all copies.

 * This software is provided "as is" without express or implied

 * warranty, and with no claim as to its suitability for any purpose.

 */

#include <iostream>

#include <map>

#include <string>

#include <iomanip>

using namespace std;

 

int main()

{

    // define multimap type as string/string dictionary

    typedef multimap<string,string> StrStrMMap;

 

    // create empty dictionary

    StrStrMMap dict;

 

    // insert some elements in random order

    dict.insert(make_pair("day","Tag"));

    dict.insert(make_pair("strange","fremd"));

    dict.insert(make_pair("car","Auto"));

    dict.insert(make_pair("smart","elegant"));

    dict.insert(make_pair("trait","Merkmal"));

    dict.insert(make_pair("strange","seltsam"));

    dict.insert(make_pair("smart","raffiniert"));

    dict.insert(make_pair("smart","klug"));

    dict.insert(make_pair("clever","raffiniert"));

 

    // print all elements

    StrStrMMap::iterator pos;

    cout.setf (ios::left, ios::adjustfield);

    cout << ' ' << setw(10) << "english "

         << "german " << endl;

    cout << setfill('-') << setw(20) << ""

         << setfill(' ') << endl;

    for (pos = dict.begin(); pos != dict.end(); ++pos) {

        cout << ' ' << setw(10) << pos->first.c_str()

             << pos->second << endl;

    }

    cout << endl;

 

    // print all values for key "smart"

    string word("smart");

    cout << word << ": " << endl;

    for (pos = dict.lower_bound(word);

         pos != dict.upper_bound(word); ++pos) {

            cout << "    " << pos->second << endl;

    }

 

    // print all keys for value "raffiniert"

    word = ("raffiniert");

    cout << word << ": " << endl;

    for (pos = dict.begin(); pos != dict.end(); ++pos) {

        if (pos->second == word) {

            cout << "    " << pos->first << endl;

        }

    }

}