# 1. Introduction of figure

• A graph is a set of nodes (or vertices) connected by edges
• Any binary relationship can be represented by a graph
• Any social network, such as Facebook, Twitter and Google +, can be represented by a graph; Diagrams can also be used to represent roads, flights, communications, etc

Concept:

A graph G=(V, E) consists of the following elements:

• 5: A set of vertices
• E: A set of edges that connect vertices in V Adjacent vertex: A vertex connected by an edge. If A and B are adjacent, A and E are not adjacent

Degree: the degree of A vertex is the number of its adjacent vertices. If A is connected to the other three vertices, the degree of A is 3

Path: a continuous sequence of vertices v 1, v2,..., vk, where vi and vi+1 are adjacent

Simple path: a simple path requires no duplicate vertices. A. D and G are a simple path; A ring is also a simple path

Directed graph:

• The edge of a directed graph has a direction
- • If there are paths between every two vertices in A graph, the graph is strongly connected. For example, C and D are strongly connected, while A and B are not strongly connected
• Weighted and unweighted graphs: # 2. Representation of drawings

Graph is often implemented by adjacency matrix. Each node is associated with an integer that will be used as the index of the array.

Use a two-dimensional array to represent the connection between vertices. If the node with index I is adjacent to the node with index j, then array [i] [j] = = 1, otherwise array [i] [j] = = 0 1. If a graph that is not strongly connected (sparse graph) is represented by an adjacency matrix, there will be many zeros in the matrix, which means that computer storage space will be wasted to represent nonexistent edges. For example, to find an adjacent vertex of a given vertex, even if the vertex has only one adjacent vertex, we have to iterate a whole row.
2. The number of vertices in the graph may change, and the two-dimensional array is not flexible. ## 2.3 incidence matrix

In the incidence matrix, the rows of the matrix represent vertices and the list shows edges.

Incidence matrix is usually used when there are more edges than vertices to save space and memory. # 3. Graph class

Skeleton of declaration class:

```class Graph {
constructor(isDirected = false) {
// The Graph constructor can receive a parameter to indicate whether the Graph is directed. By default, it is undirected
this.isDirected = isDirected;
// Use an array to store the names of all vertices in the graph
this.vertices = [];
// Use a dictionary to store adjacency tables
}
}
```

To add a new vertex to the graph:

```addVertex(v) {
// When receiving vertex v as a parameter and this vertex does not exist in the graph
if (!this.vertices.includes(v)) {
// Adds the vertex to the vertex list
this.vertices.push(v);
// In the adjacency table, set vertex v as the key, and the corresponding dictionary value is an empty array
}
};
```

```addEdge(v, w) {
// If vertex v does not exist in the graph, add it to the vertex list
}
// If the vertex w does not exist in the graph, add it to the vertex list
}
// Add an edge from vertex v to vertex W by adding w to the adjacency table of V
if (!this.isDirected) {
// Add an edge from w to v (based on undirected graph)
}
}
```

Declare the method to return the vertex list:

```getVertices() {
return this.vertices;
}
```

Declare the method to return the adjacency table:

```getAdjList() {
}
```

Test code:

```const graph = new Graph();

const myVertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];

for (let i = 0; i < myVertices.length; i++) {
}

console.log(graph.toString());
```

Implement the toString method of Graph class to output the Graph on the console:

```toString() {
let s = '';
for (let i = 0; i < this.vertices.length; i++) {
s += `\${this.vertices[i]} -> `;
for (let j = 0; j < neighbors.length; j++) {
s += `\${neighbors[j]}`;
}
s += '/n';
}
return s;
}
```

result: # 4. Graph traversal

Algorithm for traversing the graph:

2. Depth first algorithm

Graph traversal can be used to find specific vertices or paths between two vertices, check whether the graph is connected, check whether the graph contains rings, etc.

The idea of graph traversal:

• The graph traversal algorithm must track each node visited for the first time, and track which nodes have not been fully explored
• Both algorithms need to specify the first vertex to be accessed
• Fully exploring a vertex requires viewing each edge of that vertex
• The vertices connected by each edge that have not been accessed are marked as discovered and added to the list of vertices to be accessed
• In order to ensure the efficiency of the algorithm, each vertex must be visited at most twice
• Each edge and vertex in the connected graph is accessed

Differences between the two algorithms:

algorithmdata structuredescribe
Depth first algorithmStackThe vertices are stored in the stack. The vertices are explored along the path, and new adjacent vertices are accessed
breadth first algorithm queueThe vertices are stored in the queue, and the vertices that enter the queue first are explored first

When you want to label vertices that have been visited, you can use three colors to reflect their status:

• White: the vertex has not been accessed
• Gray: the vertex has been visited but not explored
• Black: the vertex has been visited and explored

You need to use the Colors variable as an enumerator:

```const Colors = {
WHITE: 0,
GREY: 1,
BLACK: 2
}
```

A helper is needed to help store whether vertices have been accessed. At the beginning of each algorithm, all vertices are marked as not accessed (white):

```const initializeColor = vertices => {
const color = {};
for (let i = 0; i < vertices.length; i++) {
color[vertices[i]] = Colors.WHITE;
}
return color;
}
```

The breadth first search algorithm will traverse the graph from the specified first vertex and access all its adjacent points (adjacent vertices) first, just like accessing one layer of the graph at a time, that is, access the vertices first wide and then deep. Steps:

1. Create a queue Q
2. Mark v as found (gray) and put v into queue Q
3. If Q is not empty, then:
1. Dequeue u from Q
2. Marked u as discovered (gray)
3. Queue u all unreached neighbors (white)
4. Marked u as explored (black)

Algorithm implementation:

```const breadthFirstSearch = (graph, startVertex, callback) => {
const vertices = graph.getVertices();
// Initialize the color array to white with the initializeColor function
const color = initializeColor(vertices);
// Declare and create a queue to store vertices to be accessed and explored
const enqueue = new Queue();

// Queue vertices
queue.enqueue(startVertex);

// If the queue is not empty
while (!queue.isEmpty()) {
// Remove a vertex from the queue through the out of queue operation
const u = queue.dequeue();
// Gets an adjacency table containing all its neighbors
// Marking the vertex gray indicates that the vertex was found but not explored
const [u] = Colors.GREY;
for (let i = 0; i < neighbors.length; i++) {
// For each adjacent point of u, its value needs to be obtained
const w = neighbors[i];
// If it hasn't been visited
if (color[w] === Colors.WHITE) {
// The label has found it and is set to gray
color[w] = Colors.GREY;
// Queue the vertex
queue.enqueue(w);
}
}
// After exploring the vertex and its adjacent vertices, mark the vertex as explored, that is, black
color[u] = Colors.BLACK;
// The breadthFirstSearch method receives a callback. This parameter is optional and will be used if a callback function is passed
if (callback) {
callback(u);
}
}
}
```

Test code:

```const printVertex = (value) => console.log('Visited vertex: ' + value);
```

result: ### 1. Use BFS to find the shortest path

Given a graph G and source vertex v, find the shortest path distance between each vertex u and V.

For a given vertex v, the breadth first algorithm will first access all vertices with a distance of 1, then vertices with a distance of 2, and so on.

• Distance from v to u [u]
• The backtracking point predecessors[u] is used to derive the shortest path from v to each other vertex U

```const BFS = (graph, startVertex) => {
const verteices = graph.getVertices();
const color = initializeColor(verteices);
const queue = new Queue();
// Represents the distance
const distances = {};
// Represents a forward tracking point
const predecessors = {};

queue.enqueue(startVertex);

// For each vertex in the graph
for(let i = 0; i < verteices.length; i++) {
// Initialize with 0 and null
distances[verteices[i]] = 0;
predecessors[verteices[i]] = null;
}

while(!queue.isEmpty()) {
const u = queue.dequeue();
color[u] = Colors.GREY;

for (let i = 0; i < neighbors.length; i++) {
const w = neighbors[i];

if (color[w] === CVolors.WHITE) {
color[w] = Colors.GREY;
// Increase the distance between v and w
distances[w] = distances[u] + 1;
// Set the forward tracking point of w to u
predecessors[w] = u;
queue.enqueue(w);
}
}
color[u] = Colors.BLACK;
}
// Returns an object containing distances and predecessors
return {
distances,
predecessors
}
}
```

## 4.2 depth first search

Start traversing the graph from the first specified vertex, follow the path until the last vertex of the path is accessed, and then back off the original path and explore the next path. The depth first search algorithm does not require a source vertex.

In the depth first search algorithm, if the vertex v in the graph is not accessed, the vertex v is accessed.

Steps:

1. Marked v as discovered (gray)
2. For all unreachable (white) adjacent points w of v, access vertex W
3. Marked v as explored (black)
```// Depth first search
// Receive a Graph class instance and callback function as parameters
const depthFirstSearch = (graph, callback) => {
const vertices = graph.getVertices();
const color = initializeColor(vertices);

// Call a private recursive function for each vertex in the instance that has not been accessed
for (let i = 0; i < vertices.length; i++) {
if (color[vertices[i]] === Colors.WHITE) {
// The parameters passed are the vertex u, color array and callback function to be accessed
}
}
};
const depthFirstSearchVisit = (u, color, adjList, callback) => {
// When you access vertex u, label it as discovered
color[u] = Colors.GREY;
// If there is a callback function, the function is executed to output the accessed vertices
if (callback) {
callback(u);
}

// Gets a list containing all adjacent points of vertex u

// For each unreachable adjacent point w of vertex u, call the depthFirstSearchVisit function and pass W and other parameters
for (let i = 0; i < neighbors.length; i++) {
const w = neighbors[i];

if (color[w] === Colors.WHITE) {
}
}
color[u] = Colors.BLACK;
}
``` If you want the depth first algorithm to traverse all nodes of graph G, build a "forest" and a set of source vertices, and output two arrays: discovery time and completion time.

• Discovery time of vertex u d[u]
• When the top point u is marked black, the completion time of u is f[u]
• Backtracking point p[u] of vertex u
```const DFS = graph => {
const vertices = graph.getVertices();
const color = initializeColor(vertices);
const d = {};
const f = {};
const p = {};
// Track discovery time and completion time
const time = { const: 0 };

// Declaration d, f, p
for (let i = 0; i < vertices.length; i++) {
f[vertices[i]] = 0;
d[vertices[i]] = 0;
p[vertices[i]] = null;
}
for (let i = 0; i < vertices.length; i++) {
if (color[vertices[i]] === Colors.WHITE) {
DFSVisit(vertices[i], color, d, f, p, time, adjList);
}
}
// Initializes the array for each vertex of the graph and returns these values at the end of the method
return {
discovery: d,
finished: f,
predecessors: p
}
};
const DFSVisit = (u, color, d, f, p, time, adjList) => {
color[u] = Colors.GREY;
// When a vertex is first discovered, track its discovery time
d[u] = ++time.count;

for (let i = 0; i < verteices.length; i++) {
if (color[w] === Colors.WHITE) {
// Tracking backtracking point
p[w] = u;
DFSVisit(w, color, d, f, p.time, adjList);
}
}
color[u] = Colors.BLACK;
// After the vertex is fully explored, track its completion time
f[u] = ++time.count;
}
```

Posted on Sun, 03 Oct 2021 14:21:32 -0400 by Sako