0% found this document useful (0 votes)
19 views34 pages

Aphs

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views34 pages

Aphs

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 34

Graph:

A Graph is a non-linear data structure consisting of vertices and edges.


The vertices are sometimes also referred to as nodes and the edges. A graph can
be defined as group of vertices and edges that are used to connect these vertices.

Or

A graph G can be defined as an ordered set G(V, E) where V(G)


represents the set of vertices and E(G) represents the set of edges which are
used to connect these vertices.

Or

A Graph is a non-linear data structure consisting of vertices and edges.


The vertices are sometimes also referred to as nodes and the edges are lines or
arcs that connect any two nodes in the graph. More formally a Graph is
composed of a set of vertices( V ) and a set of edges( E ). The graph is denoted
by G(V, E).
Graph Terminology:

Path:

A path can be defined as the sequence of nodes that are followed in order
to reach some terminal node V from the initial node U.

Closed Path:

A path will be called as closed path if the initial node is same as terminal
node. A path will be closed path if V0=VN.
Simple Path:

If all the nodes of the graph are distinct with an exception V0=VN,
then such path P is called as closed simple path.

Cycle:

A cycle can be defined as the path which has no repeated edges or vertices
except the first and last vertices.
Types Of Graphs:

1. Null Graph

A graph is known as a null graph if there are no edges in the


graph.

2. Trivial Graph:

Graph having only a single vertex, it is also the smallest graph


possible.

3. Undirected Graph
A graph in which edges do not have any direction. That
is the nodes are unordered pairs in the definition of every edge.
4. Directed Graph
A graph in which edge has direction. That is the nodes are
ordered pairs in the definition of every edge.

5. Connected Graph
The graph in which from one node we can visit any
other node in the graph is known as a connected graph.
6. Disconnected Graph:
The graph in which at least one node is not reachable
from a node is known as a disconnected graph.

7. Regular Graph:
The graph in which the degree of every vertex is equal to
K is called K regular graph.

8. Complete Graph
The graph in which from each node there is an edge to
each other node.
9. Cycle Graph:
The graph in which the graph is a cycle in itself, the degree
of each vertex is 2.

10. Cyclic Graph


A graph containing at least one cycle is known as a Cyclic
graph.

11. Directed Acyclic Graph:


A Directed Graph that does not contain any
cycle.
12. Bipartite Graph:
A graph in which vertex can be divided into two sets
such that vertex in each set does not contain any edge between them.

13.Weighted Graph:
A graph in which the edges are already specified with
suitable weight is known as a weighted graph.

Weighted graphs can be further classified as directed


weighted graphs and undirected weighted graphs.
Representation of Graphs:

There are two ways to store a graph:

1. Sequential representation (or) Adjacency matrix representation)


2. Linked list representation (or) Adjacency list representation)

Adjacency Matrix/ Sequential representation:

In this method, the graph is stored in the form of the 2D matrix


where rows and columns denote vertices. Each entry in the matrix represents
the weight of the edge between those vertices.
Example:

#include <stdio.h>
#define V 4 /* number of vertices in the graph */
void init (int arr [] [V]) /* function to initialize the matrix to zero */
{
int i, j;
for (i = 0; i < V; i++)
for (j = 0; j < V; j++)
arr[i] [j] = 0;
}
void insertEdge(int arr[][V], int i, int j) /* function to add edges to the gra
ph */
{
Arr [i] [j] = 1;
arr [j] [i] = 1;
}
void printAdjMatrix (int arr[][V]) /* function to print the matrix elements */
{
int i, j;
for (i = 0; i < V; i++)
{
printf ("%d: ", i );
for (j = 0; j < V; j++)
{
printf("%d ", arr [i] [j]);
}
printf("\n");
}
}
int main()
{
int adjMatrix[V][V];
init (adjMatrix);
insertEdge(adjMatrix, 0, 1);
insertEdge(adjMatrix, 0, 2);
insertEdge(adjMatrix, 1, 2);
insertEdge(adjMatrix, 2, 0);
insertEdge(adjMatrix, 2, 3);
printAdjMatrix(adjMatrix);
return 0;
}

Output:
0: 0 1 1 0
1: 1 0 1 0
2: 1 1 0 1
3: 0 0 1 0
Adjacency List/ Linked list representation:
This graph is represented as a
collection of linked lists. There is an array of pointer which points to the edges
connected to that vertex.

Example:

#include <stdio.h>

#include <stdlib.h>

typedef struct Node

int data;

struct Node* next;

} Node;

typedef struct Graph // Define the structure for a graph

int Vertices;

Node** adjLists;

} Graph;
Node* createNode(int data) // Function to create a new node

Node* newNode = (Node*) malloc(sizeof(Node));

if (!newNode)

printf("Memory error\n");

return NULL;

newNode->data = data;

newNode->next = NULL;

return newNode;

Graph* createGraph(int Vertices) // Function to create a graph

Graph* graph = (Graph*) malloc(sizeof(Graph));

if (!graph)

printf("Memory error\n");

return NULL;

graph->Vertices = Vertices;

graph->adjLists = (Node**) malloc(Vertices * sizeof(Node*));


for (int i = 0; i < Vertices; i++)

graph->adjLists[i] = NULL;

return graph;

void addEdge(Graph* graph, int src, int dest) // Function to add an edge to
the graph

Node* newNode = createNode(dest);

newNode->next = graph->adjLists[src];

graph->adjLists[src] = newNode;

void printGraph(Graph* graph) // Function to print the graph

for (int i = 0; i < graph-> Vertices; i++)

Node* temp = graph->adjLists[i];

printf("Adjacency list of vertex: %d: ", i);

while (temp)

printf("%d -> ", temp->data);


temp = temp->next;

printf("\n");

int main()

int Vertices = 5;

Graph* graph = createGraph(Vertices);

addEdge (graph, 0, 1);

addEdge (graph, 0, 4);

addEdge (graph, 1, 2);

addEdge (graph, 1, 3);

addEdge (graph, 1, 4);

addEdge (graph, 2, 3);

addEdge (graph, 3, 4);

printGraph(graph);

return 0;

}
Output:

Adjacency list of vertex: 0: 4 -> 1 ->


Adjacency list of vertex: 1: 4 -> 3 -> 2 ->
Adjacency list of vertex: 2: 3 ->
Adjacency list of vertex: 3: 4 ->
Adjacency list of vertex: 4:
Graph operations:

1. Insertion of Nodes/Edges in the graph – Insert a node into the graph.


2. Deletion of Nodes/Edges in the graph – Delete a node from the graph.
3. Searching on Graphs – Search an entity in the graph.
4. Traversal of Graphs – Traversing all the nodes in the graph.

Traversal:
Graph traversal is a technique used to search for a vertex in a graph.
It is also used to decide the order of vertices to be visited in the search process.
A graph traversal finds the edges to be used in the search process without
creating loops.
BFS is a traversal approach in which we first walk through all
nodes on the same level before moving on to the next level. DFS is also a
traversal approach in which the traverse begins at the root node and proceeds
through the nodes as far as possible until we reach the node with no unvisited
nearby nodes.

Breadth First Search (BFS):


Breadth-First Search, is a vertex-based technique for finding the shortest
path in the graph.
It uses a Queue data structure that follows first in first out.
In BFS, one vertex is selected at a time when it is visited and marked then
its adjacent are visited and stored in the queue.

Starting from the root, all the nodes at a particular level are visited first
and then the nodes of the next level are traversed till all the nodes are
visited.
To do this a queue is used. All the adjacent unvisited nodes of the
current level are pushed into the queue and the nodes of the current level
are marked visited and popped from the queue.

Step1:

Initially queue and visited arrays are empty.

Step2:
Push node 0 into queue and mark it visited.

Step 3:
Remove node 0 from the front of queue and visit the unvisited
neighbours and push them into queue.
Step 4:
Remove node 1 from the front of queue and visit the unvisited
neighbours and push them into queue.

Step 5:
Remove node 2 from the front of queue and visit the unvisited
neighbours and push them into queue.
Step 6:
Remove node 3 from the front of queue and visit the unvisited
neighbours and push them into queue.
As we can see that every neighbour of node 3 is visited, so move to
the next node that are in the front of the queue.

Steps 7:
Remove node 4 from the front of queue and visit the unvisited
neighbours and push them into queue.
As we can see that every neighbour of node 4 are visited, so move to
the next node that is in the front of the queue.

Now, Queue becomes empty, So, terminate this process of iteration.


Example:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_VERTICES 50
// This struct represents a directed graph using
// adjacency list representation
typedef struct Graph_t
{
int V; // No. of vertices
bool adj[MAX_VERTICES][MAX_VERTICES];
} Graph;
Graph* Graph_create(int V) // Constructor
{
Graph* g = malloc(sizeof(Graph));
g->V = V;
for (int i = 0; i < V; i++)
{
for (int j = 0; j < V; j++)
{
g->adj[i][j] = false;
}
}
return g;
}
void Graph_destroy(Graph* g)
{
free(g); // Destructor
}
void Graph_addEdge(Graph* g, int v, int w) // Function to add an edge to graph
{
g->adj[v][w] = true; // Add w to v’s list.
}
void Graph_BFS(Graph* g, int s) // Prints BFS traversal from a given source
s
{
bool visited[MAX_VERTICES]; // Mark all the vertices as not visited
for (int i = 0; i < g->V; i++)
{
visited[i] = false;
}
int queue[MAX_VERTICES]; // Create a queue for BFS
int front = 0, rear = 0;
visited[s] = true; // Mark the current node as visited and enqueue it
queue[rear++] = s;
while (front != rear)
{
s = queue[front++]; // Dequeue a vertex from queue and print it
printf("%d ", s);
// Get all adjacent vertices of the dequeued
// vertex s.
// If an adjacent has not been visited,
// then mark it visited and enqueue it
for (int adjacent = 0; adjacent < g->V; adjacent++)
{
if (g->adj[s][adjacent] && !visited[adjacent])
{
visited[adjacent] = true;
queue[rear++] = adjacent;
}
}
}
}
int main() // Driver code
{
Graph* g = Graph_create (4); // Create a graph
Graph_addEdge(g, 0, 1);
Graph_addEdge (g, 0, 2);
Graph_addEdge (g, 1, 2);
Graph_addEdge (g, 2, 0);
Graph_addEdge (g, 2, 3);
Graph_addEdge (g, 3, 3);
printf("Following is Breadth First Traversal ""(starting from vertex 2) \n");
Graph_BFS(g, 2);
Graph_destroy(g);
return 0;
}

Output:
Following is Breadth First Traversal (starting from vertex 2)
2031
Depth First Search (DFS):
The depth-first search or DFS algorithm traverses or
explores data structures, such as trees and graphs. The algorithm starts at the
root node (in the case of a graph, you can use any random node as the root
node) and examines each branch as far as possible before backtracking.

Depth first Search or Depth first traversal is a recursive algorithm for


searching all the vertices of a graph or tree data structure. Traversal means
visiting all the nodes of a graph.

Depth First Search Algorithm:


A standard DFS implementation puts each vertex
of the graph into one of two categories:
1.Visited
2.Not Visited
The purpose of the algorithm is to mark each vertex as visited while avoiding
cycles.
The DFS algorithm works as follows:
1.Start by putting any one of the graph's vertices on top of a stack.
2.Take the top item of the stack and add it to the visited list.
3.Create a list of that vertex's adjacent nodes. Add the ones which aren't in the
visited list to the top of the stack.
4.Keep repeating steps 2 and 3 until the stack is empty.
Example:
We can consider any node as the root node from the graph unless it is
specified, so let's consider node S as a root node. Firstly, we insert the
element S in the stack as shown below:

The node S has three adjacent nodes, i.e., A, B and C. Since we need to
consider only one adjacent node, it can be either A or B or C, for
traversing. Suppose if we consider node A. A is pushed into the stack and
gets printed as the result and marked as visited.

Result: S, A

Now, we need to consider the unvisited adjacent nodes of vertex A. The


unvisited adjacent vertices of node A present is only D. D is pushed into
the stack and marked visited and appended to the result as shown below:

Results: S, A, D
Above step has to be repeated for the node D.

Results: S, A, D, G
Now, consider for node G. We observe that the unvisited adjacent vertices
of node G are found to be F and E. As we can consider only one adjacent
node which is to be pushed into the stack, that can be either F or E.
Suppose if we consider node E, then E is inserted into the stack and gets
printed, and also marked as visited.

Results: S, A, D, G, E
Now, consider for node E. We observe that the unvisited adjacent vertices
of node E is only B. Therefore, B is pushed into the stack and marked
visited as shown below:
Now, consider for node E. We observe that the unvisited adjacent vertices
of node E is only B. Therefore, B is pushed into the stack and marked
visited as shown below:

Results: S, A, D, G, E, B
After inserting element B into the stack, we need to look at the unvisited
adjacent vertices of node B. As there are no unvisited adjacent vertices of
node B, it means that we cannot go any dipper into the graph. This is the
deepest position in the graph for the vertex B.
In this case, we will perform backtracking. The topmost element, i.e., B
would be popped out from the stack as shown below and will be checked
for any unexplored nodes from node B, if the unexplored nodes are not
present then the popping continues till the stack is empty.

The topmost element present in the stack is E. Since there are no


unvisited adjacent vertices left of node E; therefore, node E is popped
out from the stack as shown below:

The next topmost element present in the stack is G. Now, we need to look
for the unvisited adjacent vertices of node G. Since only one unvisited
node, i.e., F is unvisited, node F is pushed into the stack above G and
gets printed as shown below:

Now, we need to check for the adjacent vertices of node F, and observe
that the unvisited adjacent vertices of node F is C. We take vertex C and
it is pushed in to the stack as shown below:
Result: S, A, D, G, E, B, F, C
Now, we will check for the unvisited adjacent vertices of node C. Since
there is no vertex left to be visited, so we continue with backtracking of
vertices by popping them from the stack until the stack is empty
This backtracking helps in finding the elements which are unexplored.

We cannot move further F, so we need to perform backtracking. We


popped out F and searched for its unexplored adjacent nodes.

Repeat the above steps until the stack is not empty.


Once the stack is empty that indicates that the given graph is been
traversed thoroughly.
Unlike Breath First Search, Depth First Search traverses every node
in the graph twice as backtracking is applied while popping the
elements.
Here stack is used to keep the track of the path which is followed
during the traversal and this track is helpful during backtracking of the
nodes.
Final result obtained by DFS traversal of the graph taken by assuming
the node S as the root node is:

Output: S A D G E B F C
Example:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int vertex;
struct node* next;
};
struct node* createNode(int v);
struct Graph
{
int numVertices;
int* visited;
// We need int** to store a two-dimensional array.
// Similary, we need struct node** to store an array of Linked lists
struct node** adjLists;
};
void DFS(struct Graph* graph, int vertex) // DFS algo
{
struct node* adjList = graph->adjLists[vertex];
struct node* temp = adjList;
graph->visited[vertex] = 1;
printf("Visited %d \n", vertex);
while (temp! = NULL)
{
int connectedVertex = temp->vertex;
if (graph->visited[connectedVertex] == 0)
{
DFS(graph, connectedVertex);
}
temp = temp->next;
}
}
struct node* createNode(int v) // Create a node
{
struct node* newNode = malloc(sizeof(struct node));
newNode->vertex = v;
newNode->next = NULL;
return newNode;
}
struct Graph* createGraph (int vertices) // Create graph
{
struct Graph* graph = malloc(sizeof(struct Graph));
graph->numVertices = vertices;
graph->adjLists = malloc (vertices * sizeof (struct node*));
graph->visited = malloc (vertices * sizeof(int));
int i;
for (i = 0; i < vertices; i++)
{
graph->adjLists[i] = NULL;
graph->visited[i] = 0;
}
return graph;
}
void addEdge (struct Graph* graph, int src, int dest) // Add edge
{
struct node* newNode = createNode(dest); // Add edge from src to dest
newNode->next = graph->adjLists[src];
graph->adjLists[src] = newNode;
newNode = createNode(src); // Add edge from dest to src
newNode->next = graph->adjLists[dest];
graph->adjLists[dest] = newNode;
}
void printGraph(struct Graph* graph) // Print the graph
{
int v;
for (v = 0; v < graph->numVertices; v++)
{
struct node* temp = graph->adjLists[v];
printf("\n Adjacency list of vertex %d\n ", v);
while (temp)
{
printf("%d -> ", temp->vertex);
temp = temp->next;
}
printf("\n");
}
}
int main()
{
struct Graph* graph = createGraph (4);
addEdge(graph, 0, 1);
addEdge(graph, 0, 2);
addEdge(graph, 1, 2);
addEdge(graph, 2, 3);
printGraph(graph);
DFS(graph, 2);
return 0;
}
Output:
Adjacency list of vertex 0
2 -> 1 ->

Adjacency list of vertex 1


2 -> 0 ->

Adjacency list of vertex 2


3 -> 1 -> 0 ->

Adjacency list of vertexe 3


2 ->
Visited 2
Visited 3
Visited 1
Visited 0

All The Best

You might also like