Skip to content

Commit 427adfb

Browse files
committed
feat: implements breadth-first search on a graph
1 parent cf97711 commit 427adfb

File tree

2 files changed

+152
-4
lines changed

2 files changed

+152
-4
lines changed

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

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,38 @@ export class DirectedGraph {
6161
console.log(printedMessage)
6262
}
6363

64-
// eslint-disable-next-line no-unused-vars
65-
breadthFirstSearch(startingNode, searchingForNode) {}
64+
breadthFirstSearch(startingNode, searchingForNode, callback) {
65+
const visitedNodes = {}
66+
const nodesToVisitQueue = []
67+
68+
nodesToVisitQueue.push(startingNode)
69+
70+
while (nodesToVisitQueue.length > 0) {
71+
const currentNode = nodesToVisitQueue.shift()
72+
73+
if (!visitedNodes[currentNode]) {
74+
visitedNodes[currentNode] = true
75+
callback(currentNode)
76+
77+
if (currentNode === searchingForNode) {
78+
break
79+
}
80+
81+
const currentNodeNeighbors = this.nodes.get(currentNode)
82+
console.log(
83+
'currentNode:',
84+
currentNode,
85+
'currentNodeNeighbors:',
86+
currentNodeNeighbors.join(', ')
87+
)
88+
89+
currentNodeNeighbors.forEach(neighborNode => {
90+
nodesToVisitQueue.push(neighborNode)
91+
})
92+
}
93+
}
94+
}
6695

6796
// eslint-disable-next-line no-unused-vars
68-
depthFirstSearch(startingNode, searchingForNode) {}
97+
depthFirstSearch(startingNode, searchingForNode, callback) {}
6998
}

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

Lines changed: 120 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,126 @@ D ->
122122
})
123123
})
124124

125-
describe('breadthFirstSearch', () => {})
125+
describe('breadthFirstSearch', () => {
126+
it('performs a breadth-first search starting at a given node in a non-tree-like graph', () => {
127+
// A -> B
128+
// | / |
129+
// v < v
130+
// C -> D
131+
const graph = new DirectedGraph()
132+
133+
graph.addNode('A')
134+
graph.addNode('B')
135+
graph.addNode('C')
136+
graph.addNode('D')
137+
138+
graph.addEdge('A', 'B')
139+
graph.addEdge('A', 'C')
140+
graph.addEdge('B', 'C')
141+
graph.addEdge('B', 'D')
142+
graph.addEdge('C', 'D')
143+
144+
const visitedNodes = []
145+
const traversalCallback = node => {
146+
visitedNodes.push(node)
147+
}
148+
149+
graph.breadthFirstSearch('A', 'D', traversalCallback)
150+
151+
expect(visitedNodes).toEqual(['A', 'B', 'C', 'D'])
152+
})
153+
154+
it('performs a breadth-first search starting at a given node at the top of a tree and ending at the bottom right of the tree', () => {
155+
// A
156+
// B C D
157+
// E F G H I J
158+
const graph = new DirectedGraph()
159+
160+
graph.addNode('A')
161+
graph.addNode('B')
162+
graph.addNode('C')
163+
graph.addNode('D')
164+
graph.addNode('E')
165+
graph.addNode('F')
166+
graph.addNode('G')
167+
graph.addNode('H')
168+
graph.addNode('I')
169+
graph.addNode('J')
170+
171+
graph.addEdge('A', 'B')
172+
graph.addEdge('A', 'C')
173+
graph.addEdge('A', 'D')
174+
175+
graph.addEdge('B', 'E')
176+
graph.addEdge('B', 'F')
177+
178+
graph.addEdge('C', 'G')
179+
graph.addEdge('C', 'H')
180+
181+
graph.addEdge('D', 'I')
182+
graph.addEdge('D', 'J')
183+
184+
const visitedNodes = []
185+
const traversalCallback = node => {
186+
visitedNodes.push(node)
187+
}
188+
189+
graph.breadthFirstSearch('A', 'J', traversalCallback)
190+
191+
expect(visitedNodes).toEqual([
192+
'A',
193+
'B',
194+
'C',
195+
'D',
196+
'E',
197+
'F',
198+
'G',
199+
'H',
200+
'I',
201+
'J',
202+
])
203+
})
204+
205+
it('performs a breadth-first search starting at a given node at the top of a tree and ending midway through the tree without visiting every node', () => {
206+
// A
207+
// B C D
208+
// E F G H I J
209+
const graph = new DirectedGraph()
210+
211+
graph.addNode('A')
212+
graph.addNode('B')
213+
graph.addNode('C')
214+
graph.addNode('D')
215+
graph.addNode('E')
216+
graph.addNode('F')
217+
graph.addNode('G')
218+
graph.addNode('H')
219+
graph.addNode('I')
220+
graph.addNode('J')
221+
222+
graph.addEdge('A', 'B')
223+
graph.addEdge('A', 'C')
224+
graph.addEdge('A', 'D')
225+
226+
graph.addEdge('B', 'E')
227+
graph.addEdge('B', 'F')
228+
229+
graph.addEdge('C', 'G')
230+
graph.addEdge('C', 'H')
231+
232+
graph.addEdge('D', 'I')
233+
graph.addEdge('D', 'J')
234+
235+
const visitedNodes = []
236+
const traversalCallback = node => {
237+
visitedNodes.push(node)
238+
}
239+
240+
graph.breadthFirstSearch('A', 'F', traversalCallback)
241+
242+
expect(visitedNodes).toEqual(['A', 'B', 'C', 'D', 'E', 'F'])
243+
})
244+
})
126245

127246
describe('depthFirstSearch', () => {})
128247
})

0 commit comments

Comments
 (0)