Skip to content

Commit 5fef3d3

Browse files
authored
Merge pull request #4 from FSou1/features/dfs
Added depth first search algorithm
2 parents 004581d + 5bc000a commit 5fef3d3

File tree

5 files changed

+162
-2
lines changed

5 files changed

+162
-2
lines changed

src/algorithms/graph/breadth-first-search/README.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
# Breadth-first search
22

3-
TBD.
3+
Breadth-first search (BFS) is an algorithm for traversing or searching tree or graph data structures. It starts at the tree root (or some arbitrary node of a graph, sometimes referred to as a 'search key'), and explores all of the neighbor nodes at the present depth prior to moving on to the nodes at the next depth level.
4+
5+
## Applications
6+
7+
* Shortest path - in an unweighted graph, the shortest path is the path with least number of edges. With Breadth First, we always reach a vertex from given source using the minimum number of edges
8+
* Peer to peer networks - find all neighbor nodes
9+
* Crawlers in search engines - build index, start from source page and follow all links
10+
* Social networks - find people within a given distance 'k'
11+
* Broadcasting in networks - find all nodes to be reached by a broadcasting packet
12+
* Path finding - find if there is a path between two vertices
413

514
## Complexity
615

src/algorithms/graph/breadth-first-search/breadthFirstSearch.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export function breadthFirstSearch(
3434
const currentVertex = queue.dequeue();
3535
config.enterVertex(currentVertex);
3636

37-
const neighbors = currentVertex.getNeighbors();
37+
const neighbors = graph.getNeighbors(currentVertex);
3838
for (const neighbor of neighbors) {
3939
if (config.allowEnterVertex(neighbor)) {
4040
queue.enqueue(neighbor);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Breadth-first search
2+
3+
Depth-first search (DFS) is an algorithm for traversing or searching tree or graph data structures. The algorithm starts at the root node (selecting some arbitrary node as the root node in the case of a graph) and explores as far as possible along each branch before backtracking.
4+
5+
## Applications
6+
7+
* Topological sort
8+
* Cycle detection
9+
* Path finding
10+
* Solving puzzles with the only solution (e.g. mazes)
11+
12+
## Complexity
13+
14+
**Time Complexity**: TBD.
15+
16+
**Space Complexity**: TBD.
17+
18+
## References
19+
20+
- [Youtube](https://www.youtube.com/watch?v=AfSk24UTFS8);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import {Graph} from '../../../../data-structures/graph/graph';
2+
import {GraphVertex} from '../../../../data-structures/graph/graphVertex';
3+
import {GraphEdge} from '../../../../data-structures/graph/graphEdge';
4+
import {depthFirstSearch} from '../depthFirstSearch';
5+
6+
test('should perform BFS on graph', () => {
7+
const graph = new Graph(true);
8+
9+
const vertexA = new GraphVertex('A');
10+
const vertexB = new GraphVertex('B');
11+
const vertexC = new GraphVertex('C');
12+
const vertexD = new GraphVertex('D');
13+
const vertexE = new GraphVertex('E');
14+
const vertexF = new GraphVertex('F');
15+
const vertexG = new GraphVertex('G');
16+
const vertexH = new GraphVertex('H');
17+
18+
const edgeAB = new GraphEdge(vertexA, vertexB);
19+
const edgeBC = new GraphEdge(vertexB, vertexC);
20+
const edgeCG = new GraphEdge(vertexC, vertexG);
21+
const edgeAD = new GraphEdge(vertexA, vertexD);
22+
const edgeAE = new GraphEdge(vertexA, vertexE);
23+
const edgeEF = new GraphEdge(vertexE, vertexF);
24+
const edgeDH = new GraphEdge(vertexD, vertexH);
25+
26+
graph
27+
.addEdge(edgeAB)
28+
.addEdge(edgeBC)
29+
.addEdge(edgeCG)
30+
.addEdge(edgeAD)
31+
.addEdge(edgeAE)
32+
.addEdge(edgeEF)
33+
.addEdge(edgeDH);
34+
35+
expect(graph.toString()).toBe('A,B,C,G,D,E,F,H');
36+
37+
const enterVertexCallback = jest.fn();
38+
const leaveVertexCallback = jest.fn();
39+
40+
// Traverse graphs without callbacks first.
41+
depthFirstSearch(graph, vertexA);
42+
43+
// Traverse graph with enterVertex and leaveVertex callbacks.
44+
depthFirstSearch(graph, vertexA, {
45+
enterVertex: enterVertexCallback,
46+
leaveVertex: leaveVertexCallback,
47+
});
48+
49+
expect(enterVertexCallback).toHaveBeenCalledTimes(8);
50+
expect(leaveVertexCallback).toHaveBeenCalledTimes(8);
51+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/* eslint-disable no-unused-vars */
2+
import {Graph} from '../../../data-structures/graph/graph';
3+
import {GraphVertex} from '../../../data-structures/graph/graphVertex';
4+
import {GraphConfig} from '../../../data-structures/graph/graphConfig';
5+
6+
/**
7+
*
8+
*
9+
* @export
10+
* @param {Graph} graph
11+
* @param {GraphVertex} startVertex
12+
* @param {GraphConfig} config
13+
*/
14+
export function depthFirstSearch(
15+
graph: Graph,
16+
startVertex: GraphVertex,
17+
config: GraphConfig = null,
18+
): void {
19+
if (!graph) {
20+
return;
21+
}
22+
23+
if (!graph.getVertex(startVertex)) {
24+
return;
25+
}
26+
27+
config = initConfig(config);
28+
depthFirstSearchRecursive(graph, startVertex, config);
29+
}
30+
31+
/**
32+
*
33+
*
34+
* @param {Graph} graph
35+
* @param {GraphVertex} currentVertex
36+
* @param {GraphConfig} config
37+
*/
38+
function depthFirstSearchRecursive(
39+
graph: Graph,
40+
currentVertex: GraphVertex,
41+
config: GraphConfig,
42+
) {
43+
config.enterVertex(currentVertex);
44+
45+
const neighbors = graph.getNeighbors(currentVertex);
46+
for (const neighbor of neighbors) {
47+
depthFirstSearch(graph, neighbor, config);
48+
}
49+
50+
config.leaveVertex(currentVertex);
51+
}
52+
53+
/**
54+
* @param {GraphConfig} config
55+
* @return {GraphConfig}
56+
*/
57+
function initConfig(config: GraphConfig): GraphConfig {
58+
config = config || ({} as GraphConfig);
59+
config.enterVertex = config.enterVertex || ((vertex: GraphVertex) => {});
60+
config.leaveVertex = config.leaveVertex || ((vertex: GraphVertex) => {});
61+
config.allowEnterVertex = config.allowEnterVertex || isFirstEnter();
62+
return config;
63+
}
64+
65+
/**
66+
* @param {GraphVertex} vertex
67+
* @return {boolean}
68+
*/
69+
function isFirstEnter(): (vertex: GraphVertex) => boolean {
70+
const visited = {};
71+
72+
return (next: GraphVertex) => {
73+
if (!visited[next.getKey()]) {
74+
visited[next.getKey()] = true;
75+
return true;
76+
}
77+
78+
return false;
79+
};
80+
}

0 commit comments

Comments
 (0)