CS302 Lecture Notes - Quick Set and Map Example


This is a quick example of using sets and maps from the C++ Standard Template Library. The example program that I write here takes as standard input a roster file of first names and last names. An example file is in Roster.txt, which contains the names of all players in the NFL 2007 season whose last names begin with A. You'll note that the file is sorted by first name, and that there are multiple players with the same last (like Derek Anderson and Mike Anderson).

We're going to write two programs that both do the same thing -- they are going to print out the names sorted by last name, and when two last names are equal, it sorts by first name. The first program is sort_names_1.cpp:

#include <stdio.h>
#include <iostream>
#include <string>
#include <set>
#include <map>
using namespace std;

typedef set <string> fnset;

main()
{
  map <string, fnset *> lnames;
  map <string, fnset *>::iterator lnit;
  fnset *fnames;
  fnset::iterator fnit;
  int i;
  string fn, ln, name;
  
  while (!cin.eof()) {
    cin >> fn;
    if (!cin.fail()) {
      cin >> ln;
      lnit = lnames.find(ln);
      if (lnit == lnames.end()) {
        fnames = new fnset;
        lnames.insert(make_pair(ln, fnames));
      } else {
        fnames = lnit->second;
      }
      fnames->insert(fn);
    }
  }

  for (lnit = lnames.begin(); lnit != lnames.end(); lnit++) {
    fnames = lnit->second;
    for (fnit = fnames->begin(); fnit != fnames->end(); fnit++) {
      cout << *fnit << " " << lnit->first << endl;
    }
  }
}

Note, it uses a map to sort the last names. The "second" field of the map is a pointer to a set, which sorts the first names that belong to that last name. When you read in a name, you check the last name to see if it's in the map. If so, then it sets fnames to be the set of first names with that last name. If not, it creates a new fnames set and inserts it and the last name into the map. Last, it inserts the first name into the set.

When it's done reading input, it does a nested traversal to print out all of the names.

Note the typedef statement to make the program read more easily.

Note also that this program will not print out duplicate names, because sets don't hold duplicate entries. If you wanted it to print out duplicate names, you would have to use a multiset.


The second example has a struct that holds player names, and inserts the struct into a map keyed on the first name. It's a little more complex than the first example, but yields the same output. It is in sort_names_2.cpp:

#include <stdio.h>
#include <iostream>
#include <string>
#include <set>
#include <map>
using namespace std;

typedef struct {
  string fn;
  string ln;
} Player;

typedef map <string, Player *> fnmap;

main()
{
  map <string, fnmap *> lnames;
  map <string, fnmap *>::iterator lnit;
  fnmap *fnames;
  fnmap::iterator fnit;
  int i;
  string fn, ln, name;
  Player *p;
  
  while (!cin.eof()) {
    cin >> fn;
    if (!cin.fail()) {
      cin >> ln;
      p = new Player;
      p->fn = fn;
      p->ln = ln;
      lnit = lnames.find(ln);
      if (lnit == lnames.end()) {
        fnames = new fnmap;
        lnames.insert(make_pair(ln, fnames));
      } else {
        fnames = lnit->second;
      }
      fnames->insert(make_pair(fn, p));
    }
  }

  for (lnit = lnames.begin(); lnit != lnames.end(); lnit++) {
    fnames = lnit->second;
    for (fnit = fnames->begin(); fnit != fnames->end(); fnit++) {
      p = fnit->second;
      cout << p->fn << " " << p->ln << endl;
    }
  }
}