views:

111

answers:

1

Just for kind of "fun" I'm developing almost every algorithm (if possible) shown in the book Introduction to Algorithms (Cormen) in C. I've reached the graphs chapters and I'm not sure how to design my functions, but first take a look at my data structures (hope this will make clear my question).

typedef struct s_multi_matrix
    {
     int     width;
     int     height;
     int     depth;
     multi_matrix_type type; // stores either MMTYPE_INT or MMTYPE_RECORD enums to know where to read values (ivals or rvals)
     int *    ivals;
     DT_record *   rvals;
    } DT_multi_matrix;

typedef struct s_double_linked_list
    {
     DT_record * sentinel;
    } DT_double_linked_list;

typedef struct s_record // multi purpose structure
    {
     int key;
     enum e_record_type type; // stores either TYPE_INT, TYPE_SZ, TYPE_FLOAT, TYPE_VOID to know how to use the data union
     union
     {
      int  ival;
      char * sval;
      float fval;
      void * vval;
     } data;
     struct s_record * left, // for trees, disjoint sets and linked lists
         * right,
         * parent;
    } DT_record;


typedef struct s_graph  // this is the structure I'm focusing on right now
    {
     graph_type    type;  // GRAPH_DIRECTED or GRAPH_UNDIRECTED
     graph_adj_type   adj_type; // ADJ_LIST or ADJ_MATRIX
     edge_type   etype; // WEIGHTED or NOT_WEIGHTED
     union
     {
      DT_double_linked_list *  list;
      DT_multi_matrix *   matrix;
     } adjacency;
    } DT_graph;

So, I'm thinking about several functions to manipulate the DT_graph type:

// takes a pointer to a pointer to a graph, allocates memory and sets properties
void build_graph(DT_graph ** graph_ptr, graph_type gtype, graph_adj_type atype);
// prints the graph in file (using graphviz)
void print_graph(DT_graph * graph, char * graph_name);

This is the tricky part, since my graph type has several different type combinations (undirected and weighted edges, directed and weighted edges, undirected and not weighted edges, directed and not weighed edges, ...) I'm wondering which is the best approach for the functions:

void dgraph_add_wedge(DT_graph * graph, DT_record * u, DT_record * v, int weight);
void ugraph_add_wedge(DT_graph * graph, DT_record * u, DT_record * v, int weight);
void dgraph_add_nwedge(DT_graph * graph, DT_record * u, DT_record * v);
void ugraph_add_nwedge(DT_graph * graph, DT_record * u, DT_record * v);

The first two would add a weighted vertex into a directed / undirected graph and the last two would do the same thing but without any weight related to the edge. The other approach that comes to my mind looks like this:

void graph_add_edge(DT_graph * graph, DT_record * u, DT_record * v, edge_type etype, graph_type gtype);

This seems like a "golden" method for everything, and depending on the values for etype and gtype would do different operations on the graph.

Soooooooo, based upon your experiences and knowledge, what do you recommend?

BTW, I'm sure that any one has asked this before, since this is MY implementation.

+2  A: 

Pity this is plain C. With C++ several of these questions would be handled by the polymorphic features of the language. On the other hand studying algorithms that way make you focus on the algorithm/data-structure proper rather than some slick features of the language.

Anyway... My two cents:

With regards to selecting the d or u Graph Type: Why not addomg an attribute to the DT_Graph to inform the method(s) called of the graph type. After all, this is specified when the graph is created. ==> Bam! We're down to only 2 methods.

With regards to the edge weights... Maybe having two methods is preferable, API-wise : why bother the non weighed cases with the extra argument. Implementation-wise you can of course share as much of the logic as possible between all 4 cases. And frankly, once you've written all this you can still facade these behind a single "golden" method as the one you suggested.

Good luck with your coding!

mjv