Skip to content

Commit c1a2305

Browse files
committed
feat: implements depth-first search on a directed graph
1 parent 677e6ce commit c1a2305

File tree

2 files changed

+154
-1
lines changed

2 files changed

+154
-1
lines changed

src/data-structures/directed-graph/src/directed-graph.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,39 @@ export class DirectedGraph {
9595
}
9696
}
9797
}
98+
99+
depthFirstSearch(startingNode, searchingForNode, callback, showLogs) {
100+
const visitedNodes = {}
101+
const nodesToVisitStack = []
102+
103+
nodesToVisitStack.unshift(startingNode)
104+
105+
while (nodesToVisitStack.length > 0) {
106+
const currentNode = nodesToVisitStack.shift()
107+
108+
if (!visitedNodes[currentNode]) {
109+
visitedNodes[currentNode] = true
110+
callback(currentNode)
111+
112+
if (currentNode === searchingForNode) {
113+
break
114+
}
115+
116+
const currentNodeNeighbors = this.nodes.get(currentNode)
117+
118+
/* istanbul ignore next */
119+
showLogs &&
120+
console.log(
121+
'currentNode:',
122+
currentNode,
123+
'currentNodeNeighbors:',
124+
currentNodeNeighbors.join(', ')
125+
)
126+
127+
currentNodeNeighbors.forEach(neighborNode => {
128+
nodesToVisitStack.unshift(neighborNode)
129+
})
130+
}
131+
}
132+
}
98133
}

src/data-structures/directed-graph/src/directed-graph.test.js

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,5 +267,123 @@ D ->
267267
})
268268
})
269269

270-
describe('depthFirstSearch', () => {})
270+
describe('depthFirstSearch', () => {
271+
it('performs a depth-first search starting at a given node in a non-tree-like graph', () => {
272+
// A -> B
273+
// | / |
274+
// v < v
275+
// C -> D
276+
const graph = new DirectedGraph()
277+
278+
graph.addNode('A')
279+
graph.addNode('B')
280+
graph.addNode('C')
281+
graph.addNode('D')
282+
283+
graph.addEdge('A', 'B')
284+
graph.addEdge('A', 'C')
285+
graph.addEdge('B', 'C')
286+
graph.addEdge('B', 'D')
287+
graph.addEdge('C', 'D')
288+
289+
const visitedNodes = []
290+
const traversalCallback = node => {
291+
visitedNodes.push(node)
292+
}
293+
294+
graph.depthFirstSearch('A', 'D', traversalCallback)
295+
296+
expect(visitedNodes).toEqual(['A', 'C', 'D'])
297+
})
298+
299+
it('performs a depth-first search starting at a given node at the top of a tree and ending at the bottom right of the tree', () => {
300+
// A
301+
// B C D
302+
// E F G H I J
303+
const graph = new DirectedGraph()
304+
305+
graph.addNode('A')
306+
graph.addNode('B')
307+
graph.addNode('C')
308+
graph.addNode('D')
309+
graph.addNode('E')
310+
graph.addNode('F')
311+
graph.addNode('G')
312+
graph.addNode('H')
313+
graph.addNode('I')
314+
graph.addNode('J')
315+
316+
graph.addEdge('A', 'B')
317+
graph.addEdge('A', 'C')
318+
graph.addEdge('A', 'D')
319+
320+
graph.addEdge('B', 'E')
321+
graph.addEdge('B', 'F')
322+
323+
graph.addEdge('C', 'G')
324+
graph.addEdge('C', 'H')
325+
326+
graph.addEdge('D', 'I')
327+
graph.addEdge('D', 'J')
328+
329+
const visitedNodes = []
330+
const traversalCallback = node => {
331+
visitedNodes.push(node)
332+
}
333+
334+
graph.depthFirstSearch('A', 'J', traversalCallback)
335+
336+
expect(visitedNodes).toEqual(['A', 'D', 'J'])
337+
})
338+
339+
it('performs a depth-first search starting at a given node at the top of a tree and ending midway through the tree without visiting every node', () => {
340+
// A
341+
// B C D
342+
// E F G H I J
343+
const graph = new DirectedGraph()
344+
345+
graph.addNode('A')
346+
graph.addNode('B')
347+
graph.addNode('C')
348+
graph.addNode('D')
349+
graph.addNode('E')
350+
graph.addNode('F')
351+
graph.addNode('G')
352+
graph.addNode('H')
353+
graph.addNode('I')
354+
graph.addNode('J')
355+
356+
graph.addEdge('A', 'B')
357+
graph.addEdge('A', 'C')
358+
graph.addEdge('A', 'D')
359+
360+
graph.addEdge('B', 'E')
361+
graph.addEdge('B', 'F')
362+
363+
graph.addEdge('C', 'G')
364+
graph.addEdge('C', 'H')
365+
366+
graph.addEdge('D', 'I')
367+
graph.addEdge('D', 'J')
368+
369+
const visitedNodes = []
370+
const traversalCallback = node => {
371+
visitedNodes.push(node)
372+
}
373+
374+
graph.depthFirstSearch('A', 'F', traversalCallback)
375+
376+
expect(visitedNodes).toEqual([
377+
'A',
378+
'D',
379+
'J',
380+
'I',
381+
'C',
382+
'H',
383+
'G',
384+
'B',
385+
'F',
386+
])
387+
})
388+
})
271389
})

0 commit comments

Comments
 (0)