Project 1: Adjacency Lists

Due: Tuesday, February 21, 8:59:59pm


Addendum

[Wednesday Feb 15, 22:35pm] Fixed typo in operator!=.

[Monday Feb 6, 9:50am] Changes in orange.


Objectives

The objective of this programming assignment is to have you review C++ programming using following features: object-oriented design, dynamic memory allocation, pointer manipulation, exceptions and nested classes.

Introduction

In computer science and discrete mathematics, a graph is not a plot of y = f(x). A graph has vertices and edges. Here's a simple example:

The circles are the vertices and the edges are the lines between the vertices. (It is common to use the words "node" and "vertex" interchangeably, but for this project we will also have linked lists with nodes. So, we will only use "vertex" for graphs and reserve "node" for linked lists.)

In the example above, the set of vertices is {0,1,2,3,4} and the set of edges is {(3,4), (4,1), (3,0), (0,4), (0,1), (2,1), (4,2)}. It is common to use the ordered pair notation (u, v) to represent an edge, but in an undirected graph, the edges are not ordered. Thus, (2,1) and (1,2) are the same edge.

One common way to store a graph is using an adjacency list data structure. This data structure is just an array of linked lists. For example, the graph above can be stored as:

Here the first linked list, indexed by 0, has the neighbors of of vertex 0. The neighbors of a vertex v are the vertices in the graph that are connected to v by an edge. Vertices 1, 4 and 3 are the neighbors of vertex 0, so they go in the linked list indexed by 0. Similarly, vertices 2, 0 and 4 are the neighbors of vertex 1.

Note that each edge is represented twice in this data structure. For example, edge (0,3) appears once as vertex 3 in the linked list for vertex 0 and another time as vertex 0 in the linked list for vertex 3.


Assignment

Your assignment is to implement an adjacency list data structure Graph that is defined in the header file Graph.h. The Graph class provides two iterators. One iterator produces the neighbors for a given vertex. The second iterator produces each edge of the graph once.

Additionally, you must implement a test program that fully exercises your implementation of the Graph member functions. Place this program in the main() function in a file named Driver.cpp.

The purpose of an iterator is to provide programmers a uniform way to iterate through all items of a data structure using a for loop. For example, using the Graph class, we can iterate thru the neighbors of vertex 4 using:

Graph::NbIterator nit ; for (nit = G.nbBegin(4); nit != G.nbEnd(4) ; nit++) { cout << *nit << " " ; } cout << endl ;

The idea is that nit (for neighbor iterator) starts at the beginning of the list for vertex 4 and is advanced to the next neighbor by the ++ operator. The for loop continues as long as we have not reached the end of the list. We check this by comparing against a special iterator for the end, nbEnd(4). This requires the NbIterator class to implement the ++, != and * (dereference) operators.

Similarly, the Graph class allows us to iterate through all edges of a graph using a for loop like:

Graph::EgIterator eit ; pair<int,int> edge ; for (eit = G.egBegin() ; eit != G.egEnd() ; eit++) { edge = *eit ; // get current edge cout << "(" << edge.first << ", " << edge.second << ") " ; } cout << endl ;

Note that each edge is printed only once, even though it is represented twice in the adjacency list data structure.

Since a program may use many data structures and each data structure might provide one or more iterators, it is common to make the iterator class for a data structure an inner class. Thus, in the code fragments above, nit and eit are declared as Graph::NbIterator and Graph::EgIterator objects, not just NbIterator and EgIterator objects.

If you have not used nested class declarations before, here's an example: nested.cpp and sample output. (For convenience, the class declarations and implementation are provided in one file, contrary to course coding standards.)


Specifications

Here are the specifics of the assignment, including a description for what each member function must accomplish.

Requirement: other than the templated pair class, you must not use any classes from the Standard Template Library or other sources, including vector and list. All of the data structure must be implemented by your own code.

Requirement: your code must compile with the original Graph.h header file. You are not allowed to make any changes to this file. Yes, this prevents you from having useful helper functions. This is a deliberate limitation of this project. You may have to duplicate some code.

Requirement: per our course coding standards, your code must compile with g++ on the GL servers without using any compilation flags.

Requirement: a program fragment with a for loop that uses your NbIterator must have worst case running time that is proportional to the number of neighbors of the given vertex.

Requirement: a program fragment with a for loop that uses your EgIterator must have worst case running time that is proportional to the number of vertices in the graph plus the number of edges in the graph.



These are the member functions of the Graph class (not including the member functions of the inner classes).




These are the member functions of the edge iterator class EgIterator:




These are the member functions of the neighbor iterator class NbIterator. They are analogous to the functions for EgIterator.


Test Programs

The following test programs may be used to check the compatibility of your implementation. These programs do not check the correctness of your implementation. Even if your implementation compiles and runs correctly with these programs, it does not mean your implementation is error-free. Grading will be done using programs that exercise your implementation much more thoroughly. You must do the testing yourself --- testing is part of programming. Conversely, if your implementation does not compile or does not run correctly with these test programs, then it is unlikely that it will compile or run correctly with the grading programs.

These files are also available on GL in the directory:

/afs/umbc.edu/users/c/h/chang/pub/www/cs341.s17/projects/proj1files/


Implementation Notes


What to Submit

You must submit the following files to the proj1 directory.

You do not need to submit Graph.h because it should not have changed. If you do happen to place a copy of Graph.h in your submission directory, it will be replaced by a copy of the original version.

If you followed the instructions in the Project Submission page to set up your directories, you can submit your code using this Unix command command.

cp Graph.cpp Driver.cpp ~/cs341proj/proj1/