// Read the TCS Genealogical Database file and display its tree structure // using indentation, with names ordered by Ph.D. date. #include #include #include #include #include #include #include #include using namespace std; typedef map data_map; struct earlier: binary_function { bool operator()(const string& name1, const string& name2) const { return dates[name1] < dates[name2]; } static data_map dates; // dates[name] holds year in which Ph.D. degree was // granted to name static data_map places; // places[name] holds institution that granted Ph.D. }; data_map earlier::dates; data_map earlier::places; typedef multiset date_ordered_mset; typedef map relation_map; void output_tree(const string& name, relation_map& students, data_map& places, data_map& dates, int indentation_level = 0) { for (int k = 0; k != indentation_level; ++k) cout << " "; cout << name << " (" << places[name] << " " << dates[name] << ")" << endl; date_ordered_mset& L = students[name]; date_ordered_mset::const_iterator j; for (j = L.begin(); j != L.end(); ++j) output_tree(*j, students, places, dates, indentation_level + 1); } void get_chunk(istream& in, string& s, char terminator = '\t') { s.erase(s.begin(), s.end()); s.reserve(20); string::value_type ch; while (in.get(ch) && ch != terminator) s.insert(s.end(), ch); } int main() { cout << "Displaying the SIGACT " << "Theoretical Computer Science Genealogy" << endl; cout << "First, enter the name of the file containing\n" << "the genealogy data: " << flush; string file_name; cin >> file_name; ifstream ifs(file_name.c_str()); if (!ifs.is_open()) { cout << "Eh? Could not open file named " << file_name << endl; exit(1); } relation_map advisors, students; string name, advisor, place, date; while (true) { // ignore comments if (ifs.peek() == '#') { get_chunk(ifs, name, '\n'); continue; } get_chunk(ifs, name); if (!ifs) break; get_chunk(ifs, advisor); get_chunk(ifs, place); get_chunk(ifs, date, '\n'); earlier::places[name] = place; earlier::dates[name] = date; if (advisor == "?") advisor = "---"; students[advisor].insert(name); advisors[name].insert(advisor); } date_ordered_mset& roots = students["---"]; relation_map::iterator i; date_ordered_mset::iterator j; bool any_advisor; for (i = advisors.begin(); i != advisors.end(); ++i) { any_advisor = false; for (j = i->second.begin(); j != i->second.end(); ++j) { if (*j == string("---") || advisors.find(*j) != advisors.end()) any_advisor = true; } if (!any_advisor) { string first_advisor = *(i->second.begin()); // Check if it is already there: // must do linear search with generic find, since multiset // is ordered based on dates rather than names (but the // multiset size is not big enough for this to be a // problem). if (find(roots.begin(), roots.end(), first_advisor) == roots.end()) roots.insert(first_advisor); } } for (j = roots.begin(); j != roots.end(); ++j) output_tree(*j, students, earlier::places, earlier::dates); return 0; }