You are on page 1of 4

# Week 7 Tutorial: Graphs

Stage 1: fill out and implement the ADTs (we write AIs in Round 2)
Design decision as to what to put in the struct
Call stuff from GameView, but neither player calls from GameView directly
Cant modify header files and their signatures in Round 1. In Round 2 (AI), you are
welcome to
change stuff as you like.

Q3
Path: sequence of edges (connected by one another)
Shortest path is 1 edge
Cycle: edges bring you back to the same starting vertex
e.g. in tutorial: abcdefghikja
Tree: graph without any cycles
From the current graph, delete all edges that make it not a tree
e.g. delete the star, b-f, i-k, k-h
Spanning tree: a tree able to reach every node
Clique: totally connected subgraph - i.e. fully connected
Every node connected to every other node by a single edge
e.g. bcdef is a clique
e.g. smallest clique: a triangle
Q4.
1
0

3
2
4

(a).
6 vertices: therefore 6x6 matrix
012345
weight.
0

011

1
2
3
4
5

10 1
1
11
11
1
1
1

## Undirected graph = symmetry. For one edge, need to change 2 variables.

Directed graph: one side represents from, one side represents to.
Uses a lot of space. Size of matrix: V * V => huge, but if few connections, only one
entry.
Complete waste of space if there are few edges
(b).
Adjacency list representation: a jagged list of lists
0
12

1
02

2
034

3
12

4
25

5
4

6
- array of ptrs
null

## (and then each linked list goes to NULL)

Again, represented twice for an undirected graph. And only once for a directed
graph.
More space efficient: space used = twice the amount of edges (for undirected) that
exist
There is a certain point where adjacency lists will use more memory than matrices.
Worse time complexity: need to scan through each list.
Q6.
Write a function to count the number of edges in a graph:
int nEdges (Graph g)
{
int count = 0;
for (int i = 0; i < g->nV; i++) {
for (int j = i+1; j < g->nV; j++) {
count += g->edges[i][j];
}
}

// triangle method
// could also count weight

}
Consider a triangle of the matrix
Could count all 1s, and divide by 2 (need to check no node points to itself or handle it
otherwise)
Q11.
BFS: explore nodes closest to it
DFS: go far away
Writing each one is the same - just that one uses a queue and one uses a stack.
BFS for example graph in q11:

## current node queue

===================
nothing
0
0
1
- 1 is neighbour of 0
(visited: 0)
1
234
- could add 1 to the queue and check later
visited: (0,
1)
2
3435
- 1 is in visited but 3 isnt, so duplicate, but possible to
implement
some way to avoid this
visited: (0,1,5)
3
43545
visited: (0,1,5,3)
4
35455
etc. put 4 in visited
3
5455
5
45567

67
6
7
- 6 has no neighbouring nodes
7
nothing - finished BFS

DFS:
current node queue
===================
nothing
0
0
1
1
234

4
5
7
out.

2335
67
nothing

## - goes deeper into the graph first, then goes back

Again, can have visited[] to prevent repeats.

## DFS can be written recursively because it uses a stack:

ex. (but eats up your stack frame - stack overflow)
void explore (current_node):
for all the current nodes neighbours:
visit neighbour
No need to write up a stack - we just borrow the stack in memory