Basic Graphs Terminology
What
is a graph ? The name may suggest something that
has to do with graphics, which in a way is true but graphs are
generally more than that. Their main use is at describing relationships
between various entities in the real world. For example consider
four persons - call them Mary, John, April and George. Now let us
try to examine the relationships between them. For this we will
use arrows with the following convention - we have an arrow going
from X to Y if X likes Y,
otherwise no arrow at all. Consider the following - John likes
April, April likes John, Mary likes George, George likes April,
Mary likes John - and draw the diagram below.

With
this overall view we may more easily arrive at certain
conclusions. It is now obvious that April and John are the most
"liked" persons, while there is nobody who likes Mary.
Also we see that the relationship between John and April is
reciprocal. In the following we will define some basic graph
terminology based on the previous example.
A vertex
(or node) is the representation of an entity in
the real world as part of a network of such entities, where each
may be connected to another on the basis of a particular
relation. This connection is indicated with an edge
(or arc) drawn between the corresponding
vertices. In the above diagram, the vertices are the circles -
(John), (Mary), (George), (April) - while edges are denoted by
arrows. Because replacing names (or any other kind of information
describing the entity) with consecutive numbers does
not affect the initial graph and the conclusions we may get based
upon it, we might as well use the following diagram :

Now
we can give a more rigorous definition of the graph - an ordered
pair of sets G = ( X, U ) where
X
= vertex set = { 1, 2, ..., n } , n
= number of vertices
U = edge set = { ( x,
y ) | x, y are from X and
there is an edge between x and y }
For
example, the previous graph has X = { 1, 2, 3, 4 }
and U = { ( 1, 2 ), ( 2, 1 ),
( 3, 1 ), ( 4, 2 ), (
4, 3 ) } or as in the initial formulation :
X
= { April, John, George, Mary } and U = { (
April, John ), ( John, April ), ( George, April ), ( Mary,
John ), ( Mary, George ) }
So far the edges we
have drawn were arrows with a specific direction (George likes
April, but April does not like George). From now
on we will only consider reciprocal relationships as between John
and April. Also we will use line segments instead of arrows.
These are in fact bidirectional arrows and whenever we have a
line from x to y we should bear in mind that it
is actually formed of two edges ( x, y ) and ( y, x
).
We may now give the
definition of an undirected graph - an ordered
pair of sets G = ( X, U ) where
X = vertex
set = { 1, 2, ..., n }, n = number of
vertices
U = edge set = { ( x, y ) | x,
y are from X and there is a bidirectional arrow
between x and y }

For example, the
undirected graph above has X = { 1, 2, 3, 4, 5
} and U = { ( 1, 2 ), ( 1, 4 ), ( 2,
3 ), ( 4, 5 ) }.
Now it would be nice
if we found a method of storing such data structures in the
memory of a computer. But before we do that let us try and
optimize things a little bit - look at the vertex set X,
is it really necessary to keep all elements 1, 2, ..., n
? Or is it possible to replace the set X by a single
value n, the number of vertices of the graph ? Of course
it is possible. This means that an arbitrary undirected graph is
only identified by an ordered pair G = ( n, U ) where U
is defined as above.
The adjacency
matrix is a square binary matrix (its elements are
either 0 or 1) of order n (this is the number of graph
vertices) with the following property :
A(
i, j ) = 1 if the ( i, j ) pair is
found in the edge set U, otherwise A(
i, j ) = 0, for all values 1 <= i, j
<= n
It is easy to see
that this matrix is symmetric since whenever we have a ( i, j
) pair we also have its corresponding ( j, i ) pair -
remember the graph is undirected. We have therefore found a
method of storing a graph into a square binary matrix which is
easy to store in memory. Next we will implement a C++ class Graph
that uses stream operators to initialize and display the contents
of a graph stored as an adjacency matrix. Also, the isConnected
function tests for the connectivity of two vertices in the graph.
#include <iostream.h>
class Graph {
public:
Graph(int size = 2);
~Graph();
bool isConnected(int, int);
friend istream& operator>>(istream&, Graph&);
friend ostream& operator<<(ostream&, Graph&);
private :
int n;
int **A;
};
Graph::Graph(int size) {
int i, j;
if (size < 2) n = 2;
else n = size;
A = new int*[n];
for (i = 0; i < n; ++i)
A[i] = new int[n];
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
A[i][j] = 0;
}
Graph::~Graph() {
for (int i = 0; i < n; ++i)
delete [] A[i];
delete [] A;
}
bool Graph::isConnected(int x, int y) {
return (A[x-1][y-1] == 1);
}
istream& operator >> (istream &in, Graph &G) {
int p, x, y;
cout << "Input number of edges : ";
in >> p;
cout << endl << "Input edges :" << endl;
for (int i = 0; i < p; ++i) {
cout << "Edge " << i+1 << endl;
cout << " x = ";
in >> x;
cout << " y = ";
in >> y;
--x; --y;
G.A[x][y] = G.A[y][x] = 1;
}
return in;
}
ostream& operator << (ostream &out, Graph &G) {
int i, j;
out << endl;
out << "Adjacency matrix : " << endl << endl;
for (i = 0; i < G.n; ++i) {
for (j = 0; j < G.n; ++j)
out << G.A[i][j] << " ";
out << endl;
}
return out;
} |
It is time to test
our class :
void main() {
int a, x, y;
cout << "Input number of vertices : ";
cin >> a;
Graph g(a);
cin >> g;
cout << g;
cout << endl << "Test for connectivity" << endl << endl;
cout << " Input first node : ";
cin >> x;
cout << "Input second node : ";
cin >> y;
cout << endl << x << " and " << y;
if (g.isConnected(x, y)) cout << " are connected." << endl;
else cout << " are not connected." << endl;
}
|
To conclude, we
have found a way of storing a graph in memory and test for the
connectivity of two vertices. This may not seem such a great
achievement but there are actually lots of applications that
require this simple test. Remember that graphs are about
relationships and relationships arise everywhere around us.