Graph Adt

4
Implementing a Graph ADT Ramprasad Joshi October 13, 2011 Abstract Implementing an ADT has two interacting parts: abstracting away the essence of the data structure from implementation-dependent details, and implementing it in such a way that the presented data structure does not reveal those details. Though we will seek to implement a Graph ADT in C here, the same can be easily ported to other, more advanced programming languages. 1 The Essence of Graphs The most important common features of graphs as a data structure are: 1. That each graph is a binary relation on a finite set. Usually, it is irreflexive. If it is symmetric, the graph is undirected, else directed. 2. The elements of the set, called vertices, and the pairs in the relation, called edges, must be accessible individually. 3. Queries on whether two vertices are related (connected by an edge) should be answerable as a single operation. We can represent any finite set by just remembering that it has the same form as the set of first n positive natural numbers, where n is the size of the set. Thus n captures all we need to know about the set of vertices V in abstract. In concrete, we may label the vertices as we like, and we may also attach more attributes, such as colors and suchlike to them, as suggested by the reference book. Edges E can be represented by either assuming that no pair of vertices is in the relation unless specified (the adjacency list representation), or by assign- ing explicit yes-no values to each possible pair in V × V (the adjacency matrix representation). We will not commit ourselves to any of the two, as also to whether the edges are weighted (and/or have other attributes as well) or not. Let us summarize this into a header file: /* Header GraphBase.h */ #ifndef GRAPH_BASE_H #define GRAPH_BASE_H typedef enum { True=-1, Yes=1, False=0, No=0 } Bool; typedef struct _graph { 1

description

graph adt

Transcript of Graph Adt

Implementing a Graph ADT

Ramprasad Joshi

October 13, 2011

Abstract

Implementing an ADT has two interacting parts: abstracting away theessence of the data structure from implementation-dependent details, andimplementing it in such a way that the presented data structure does notreveal those details. Though we will seek to implement a Graph ADT in Chere, the same can be easily ported to other, more advanced programminglanguages.

1 The Essence of Graphs

The most important common features of graphs as a data structure are:

1. That each graph is a binary relation on a finite set. Usually, it is irreflexive.If it is symmetric, the graph is undirected, else directed.

2. The elements of the set, called vertices, and the pairs in the relation, callededges, must be accessible individually.

3. Queries on whether two vertices are related (connected by an edge) shouldbe answerable as a single operation.

We can represent any finite set by just remembering that it has the sameform as the set of first n positive natural numbers, where n is the size of the set.Thus n captures all we need to know about the set of vertices V in abstract.In concrete, we may label the vertices as we like, and we may also attach moreattributes, such as colors and suchlike to them, as suggested by the referencebook. Edges E can be represented by either assuming that no pair of vertices isin the relation unless specified (the adjacency list representation), or by assign-ing explicit yes-no values to each possible pair in V × V (the adjacency matrixrepresentation). We will not commit ourselves to any of the two, as also towhether the edges are weighted (and/or have other attributes as well) or not.

Let us summarize this into a header file:

/* Header GraphBase.h */

#ifndef GRAPH_BASE_H

#define GRAPH_BASE_H

typedef enum { True=-1, Yes=1, False=0, No=0 } Bool;

typedef struct _graph {

1

int vertices;

void *edges;

char **labels;

void *vattributes;

void *eattributes;

void* (*VertexAttribute)(Graph g, int AttributeNumber, int Vertex);

void* (*EdgeAttribute)(Graph g, int AttributeNumber, int Vertex1, int Vertex2);

void* (*SetVertexAttribute)(Graph g, int AttributeNumber,

int Vertex, void *Attribute);

void* (*SetEdgeAttribute)(Graph g, int AttributeNumber, int Vertex1,

int Vertex2, void *Attribute);

}

*Graph;

extern Graph InitGraph(int vertices);

extern void PrintGraph(Graph g);

extern Bool Edge(Graph g, int Vertex1, int Vertex2);

extern void *DefaultVertexAttribute(int AttributeNumber, int Vertex, Graph g);

extern void *EdgeAttribute(int AttributeNumber, int Vertex1, int Vertex2, Graph g);

extern void DefaultSetVertexAttribute(Graph g, int AttributeNumber,

int Vertex, void *Attribute);

extern void DefaultSetEdgeAttribute(Graph g, int AttributeNumber,

int Vertex1, int Vertex2, void *Attribute);

extern Graph AddVertex(Graph g);

extern Graph AddEdge(Graph g, int Vertex1, int Vertex2);

#endif /* GRAPH_BASE_H */

A corresponding C source file can be:

/* GraphDefault.c source */

#include "GraphBase.h"

#include <stdio.h>

#include <stdlib.h>

#include <error.h>

#include <errno.h>

#include <malloc.h>

void *MyMalloc(size_t n)

{

void *p = malloc(n);

if(p == NULL) error(-1,errno,"Memory Shortage");

return p;

}

Graph InitGraph(int vertices)

2

{

Graph g = (Graph)MyMalloc(sizeof(struct _graph));

g->vertices = vertices;

g->edges = MyMalloc(sizeof(int)*vertices*vertices); /* Adjacency Matrix */

g->labels = (char**)MyMalloc(sizeof(char*)*vertices);

int i;

for(i = 0; i < vertices; i++)

{

g->labels[i] = (char*)MyMalloc(2);

g->labels[i][0] = ’A’+i;

}

}

Tuesday 11 Oct 2011: Implement this and also some base functions likePrintGraph. Implement a testing main and add some test functions for specificaspects of the implementation.

Now we can allow different graph representations by providing an Edge func-tion pointer in the struct graph as a member, and assigning the appropriateEdgeFromList or EdgeFromMatrix function to the pointer for each instance ofa graph. The added member to the struct graph would look like:

typedef struct _graph {

...

Bool (*Edge)(struct _graph *g, int Vertex1, int Vertex2);

...

} *Graph;

}

and the functions and assignments:

Bool EdgeFromList(Graph g, int Vertex1, int Vertex2)

{

Link *edges = (Link*)(g->edges);

return Search(edges[Vertex1],Vertex2);

}

Bool EdgeFromMatrix(Graph g, int Vertex1, int Vertex2)

{

int **edges = (int**)(g->edges);

return edges[Vertex1][Vertex2] ? Yes : No;

}

...

...

/* in some function */

Graph g = InitGraph(n);

g->edges = InitMatrix(g,n);

g->Edge = EdgeFromMatrix;

Graph h = InitGraph(m);

h->edges = InitList(h,m);

3

h->Edge = EdgeFromList;

...

/* Now g, h can be passed as Graph objects anywhere -- suppose as a graph G -- and then the called function can have : */

if(G->Edge(3,8))

{

...

}

/* ... etc. */

Thursday 13 Oct 2011 : Implement this, and more ...!

4