Please send questions to st10@humboldt.edu .
/************************************************************/
/* ADAPTED FROM:                                            */
/* http://www.cs.colorado.edu/~main/chapter12/table2.h      */
/*                                                          */
/* Main and Savitch, "Data Structures and Other Objects     */
/*    using C++", 2nd edition, Addison-Wesley, Ch.12, p.587 */
/************************************************************/

//-----------------------------------------------------------
// File: graph.template
// Name: Michael Main, Walter Savitch
//       (adapted by Sharon M. Tuttle)
// last modified: 4-27-05
//
// Template Class: graph<Item> (a graph where each vertex has
//                 a label of type Item; this label may be
//                 any of the C++ built-in types or any class
//                 with a default constructor and an assignment
//                 operator. The graph may not have multiple
//                 edges between two vertices.
//
// VALUE SEMANTICS for the graph<Item> template class:
//    Assignments and the copy constructor may be used 
//       with graph<Item> objects.
//
// DYNAMIC MEMORY USAGE by the graph<Item> template class:
//    If there is insufficient dynamic memory, then the
//       following functions throw bad_alloc:
//       constructor, the copy constructor, add_edge,
//       add_vertex, and the assignment operator. [I THINK]
//-----------------------------------------------------------

#include "graph.h"
#include <iostream>
#include <cassert>
#include <algorithm>   // for copy...
using namespace std;

/**********************************************************/
/* CONSTRUCTORS and DESTRUCTOR                            */
/**********************************************************/

// constructor
//
// postcondition: initializes a graph with no vertices
//    and no edges.
//
template <typename Item>
graph<Item>::graph( )
{
    total_vertices = 0;
    total_edges = 0;

    // arrays adj_to_vertex and vertices are not dynamic,
    //    in this case. If they were, I'd need to initialize
    //    them to the desired size here. But, since they are
    //    not dynamic, they were declared in the private part
    //    in graph.h to size MAXIMUM.

    // BUT --- I do need to make all of the adj_to_vertex
    //    pointers NULL, to start;
    for (int i=0; i < graph<Item>::MAXIMUM; i++)
    {
        adj_to_vertex[i] = NULL;
    }
}

// copy constructor
//
template <typename Item>
graph<Item>::graph(const graph<Item>& source)
{
    total_vertices = source.total_vertices;
    total_edges = source.total_edges;

    // copy over vertex labels
    copy(source.vertices, source.vertices + total_vertices, vertices);

    // copy over edge lists
    node<Item> *tail_ptr; // needed for argument of list_copy

    for (int i=0; i<MAXIMUM; i++)
    {
        list_copy(source.adj_to_vertex[i], adj_to_vertex[i], 
                  tail_ptr);
        tail_ptr = NULL;
    }
}

template <typename Item>
graph<Item>::~graph( )
{
    for (int i=0; i<total_vertices; i++)
    {
        list_clear(adj_to_vertex[i]);
    }
}

/*******************************************************/
/* ACCESSORS and other constant member functions       */
/*    (observers)                                      */
/*******************************************************/

// get_num_vertices
//
// postcondition: returns the number of vertices in
//    the graph.
//
template <typename Item>
size_t graph<Item>::get_num_vertices( ) const
{  
    return total_vertices;
}

// get_num_edges
//        
// postcondition: returns the number of edges in the
//    graph.
//
template <typename Item>
size_t graph<Item>::get_num_edges( ) const
{
    return total_edges;
}
        
// is_vertex
//
// postcondition: returns true if vert is the label of
//    a vertex in this graph; returns false otherwise.
//
template <typename Item>
bool graph<Item>::is_vertex(Item vert) const
{
    bool found = false;

    // look through vertices, seeing if this label
    //    is there. Short-circuit (exit immediately)
    //    if vert is found...
    for (int i=0; i < total_vertices; i++)
    {
        if (vertices[i] == vert)
        {
            return true;
        }
    }
        
    // if reach here --- vert is NOT one of this graph's 
    //    vertices.
    return false;
}

// is_edge
//
// preconditions: is_vertex(source) == true,
//        is_vertex(target) == true
// postconditions: returns true if (source, target) is
//        an edge in this graph, and returns false otherwise.
//
template <typename Item>
bool graph<Item>::is_edge(Item source, Item target) const
{
    assert (is_vertex(source) == true);
    assert (is_vertex(target) == true);

    size_t source_index = get_vert_index(source);

    node<Item> *curr;

    curr = adj_to_vertex[source_index];

    // is target in source's list of adjacent vertices?
    while ((curr != NULL) && (curr->get_data( ) != target))
    {
        curr = curr->get_next( );
    }

    if (curr == NULL)
    {
        // target was not in source's adjacency list
        return false;
    }
    else
    {
        // target must have been in source's adjacency list
        return true;
    }
}

// get_neighbors
//
// precondition: is_vertex(vert) == true
// postcondition: returns a set containing all of the
//    labels of vertices that are the target of an edge
//    whose source is vert.
//
template <typename Item>
set<Item> graph<Item>::get_neighbors(Item vert) const
{
    set<Item> neighbor_set;

    size_t vert_index = get_vert_index(vert);

    node<Item> *curr;

    curr = adj_to_vertex[vert_index];

    // add all adjacent vertices to neighbor_set
    //    for this vertex
    while (curr != NULL)
    {
        neighbor_set.insert( curr->get_data( ) );
        curr = curr->get_next( );
    }

    return neighbor_set;
}

// print_graph
//
// postcondition: prints the graph in the following
//    form: first the set of vertices, then the edges
//    between the vertices.
//
template <typename Item>
void graph<Item>::print_graph( ) const
{
    node<Item> *curr;
    Item       curr_vertex;
    size_t     curr_vertex_index;

    cout << "printing vertices and edges of graph: " << endl;
    cout << "-----------------------------------------" << endl;

    // print vertices...
    cout << "V = {";

    for (int i=0; i<total_vertices; i++)
    {
        cout << vertices[i] << "  ";
    }

    cout << "} " << endl;

    // now print edges...
    cout << endl;
    cout << "E = {";
    
    for (int i=0; i<total_vertices; i++)
    {    
        if (adj_to_vertex[i] != NULL)
        {
            curr_vertex = vertices[i];
            curr = adj_to_vertex[i];

            while (curr != NULL)
            {
                cout << "(" << curr_vertex << ",";
                cout << (curr->get_data( )) << ")  ";
                curr = curr->get_next( );
            }

            // "offset" edges adjacent from each vertex
            cout << endl << "     ";
        }
    }

    cout << "} " << endl;
}

//***************************************************/
/* MODIFIERS and other modifying member functions   */
//***************************************************/

// add_vertex
//
// preconditions: get_num_vertices( ) < MAXIMUM,
//                is_vertex(new_vert) == false
// postconditions: the number of vertices in the graph 
//    has been increased by adding vertex new_vert, which
//    currently has no edges.
//
template <typename Item>
void graph<Item>::add_vertex(const Item& new_vert)
{
    assert (get_num_vertices( ) < graph<Item>::MAXIMUM);
    assert (is_vertex(new_vert) == false);

    size_t new_vert_index = total_vertices;
    total_vertices++;

    // probably don't NEED to do this --- but, to play it
    //    safe, make SURE that this vertex CLEARLY has no
    //    adjacent vertices yet
    adj_to_vertex[new_vert_index] = NULL;

    // DO need to add this vertex to vertices array!
    vertices[new_vert_index] = new_vert;
}

// add_edge
//
// preconditions: is_vertex(source) == true,
//                is_vertex(target) == true
// postconditions: if there was not an edge from
//    source to target before, then there is, now
//    (and the number of edges has been increased).
//    (If there was an edge from source to target
//    before, then the graph is unchanged.)
//
template <typename Item>
void graph<Item>::add_edge(Item source, Item target)
{
    size_t source_index, target_index;

    // if this edge already exists, no action is needed.
    if (is_edge(source, target))
    {
        return;
    }

    // IF reach here, however, this edge SHOULD be added
    source_index = get_vert_index(source);
    target_index = get_vert_index(target);

    list_head_insert(adj_to_vertex[source_index], target);
    list_head_insert(adj_to_vertex[target_index], source);

    total_edges++;
}

// remove_edge
//
// preconditions: is_vertex(source) == true,
//                is_vertex(target) == true
// postconditions: if there was an edge from source
//    target before, then it has now been removed
//    (and the numberof edges has been decreased).
//    (If there had not been an edge from source to
//    target before, then the graph is unchanged.)
//
template <typename Item>
void graph<Item>::remove_edge(Item source, Item target)
{
    size_t source_index, target_index;

    assert( is_vertex(source) == true );
    assert( is_vertex(target) == true );

    // if this is not currently an edge, no action is needed
    if ( ! is_edge(source, target) )
    {
        return;
    }

    // IF reach here, though, this edge DOES exist in graph
    total_edges--;

    source_index = get_vert_index(source);
    target_index = get_vert_index(target);
    
    node<Item> *curr;
    node<Item> *prev = NULL;

    // ICK alert: the below should be TWO calls to
    //    a helper function!!!!!

    // remove target from source's adjacency list
    curr = adj_to_vertex[source_index];

    // if target is head of list...
    if (curr->get_data( ) == target)
    {
        list_head_remove(adj_to_vertex[source_index]);
    }
    else
    {
        // target is "later" in list;

        while (curr->get_data( ) != target)
        {
            prev = curr;
            curr =  curr->get_next( );
        }

        // cannot reach here unless curr->get_data( ) == target

        // set node before target node to point to
        //    node after target
        prev->set_next( curr->get_next( ) );

        delete curr;
        curr = NULL;
    }

    // remove source from target's adjacency list
    curr = adj_to_vertex[target_index];

    // if source is head of list...
    if (curr->get_data( ) == source)
    {
        list_head_remove(adj_to_vertex[target_index]);
    }
    else
    {
        // source is "later" in list;

        while (curr->get_data( ) != source)
        {
            prev = curr;
            curr =  curr->get_next( );
        }

        // cannot reach here unles curr->get_data( ) == source

        // set node before source node to point to
        //    node after source
        prev->set_next( curr->get_next( ) );

        delete curr;
        curr = NULL;
    }
}

/****************************************************/
/* OVERLOADED OPERATORS                             */
/****************************************************/

// operator =
//
// postcondition: the graph that activated this
//    will be made to have the same vertices and
//    edges as source
//
template <typename Item>
void graph<Item>::operator =(const graph<Item>& source)
{
    node<Item> *tail_ptr;

    if (this == &source)
        return;

    copy(source.vertices, source.vertices + source.total_vertices, 
         vertices);

    for (int i=0; i<graph<Item>::MAXIMUM; i++)
    {
        list_clear(adj_to_vertex[i]);
    }

    for (int i=0; i<source.total_vertices; i++)
    {
        list_copy(source.adj_to_vertex[i], adj_to_vertex[i], tail_ptr);
        tail_ptr = NULL;
    }
    total_vertices = source.total_vertices;
    total_edges = source.total_edges;
}

/****************************************************/
/* PRIVATE HELPER MEMBER FUNCTIONS                  */
/****************************************************/

// get_vert_index
//
// precondition: is_vertex(vert) == true
// postconditions: returns the index into adj_to_vert
//    for vertex vert.
//
template <typename Item>
size_t graph<Item>::get_vert_index(Item vert) const
{
    assert( is_vertex(vert) == true );

    // look to find where vert is found in vertices array
    //    (note: this WILL stop early, once vert is found)
    for (int i=0; i < total_vertices; i++)
    {
        if (vertices[i] == vert)
        {
            return i;    // i is vert's index in vertices
        }
    }
}