The graph
A graph is a set of nodes joined by edges. Here, 7 nodes and 8 edges. Each node keeps a list of its neighbours, the nodes one edge away. To search is to visit every node you can reach from A.
Breadth-first
Breadth-first search keeps a queue: a line where the first in is the first out. It puts A in the queue and in the seen set, the record of every node already found. A is 0 edges from A.
Each round takes the node at the front of the queue and looks at its neighbours. A leaves; B and C have not been seen, so they join the back of the queue. They are 1 edge from A.
B comes out and adds D and E; C comes out and adds F. All three are 2 edges from A. Because the queue is first in, first out, BFS finishes every node at one distance before it starts the next.
D adds G. Then E and F also lead to G, but G is already in the seen set, so it is not added again. Without that check, a graph with loops would send the search round in circles forever.
G comes out, the queue is empty, and BFS is done: order A B C D E F G. A node is first found by a shortest route, so each number is the fewest edges from A. G is 3 away: A, B, D, G.
Depth-first
Depth-first search starts again at A and follows one path as far as it can; each number now shows how deep it is. With recursion, dfs(A) calls dfs(B), which calls dfs(D), then dfs(G). The open calls form a stack: last in, first out.
At G, D is seen, so it goes to E. Both of E's neighbours are already seen: a dead end. dfs(E) returns, E comes off the top of the stack, and the search backs up to G. This is called backtracking.
From G it dives again: F, then C. C's neighbours are seen, so the calls return one by one and the stack empties. DFS visited A B D G E F C, a different order from BFS on the same graph.
Compare
Each number is how deep DFS was when it found that node. It reached C 5 edges down, but C is 1 edge from A. Only BFS promises the fewest edges. DFS suits finding a way through a maze, or spotting loops.
Both searches handle each node once and look along each edge from both ends: 7 nodes and 16 neighbour checks here. So their work grows with nodes plus edges, written O(V + E), where V counts nodes and E edges.
If edges have costs, fewest edges may not be cheapest. A, B, D costs 6; A, C, F, G, D costs 4. Dijkstra's algorithm takes the cheapest node next, from a priority queue; each number is its cost. OSPF routers use it.
The same thing in Python
# step 1/12 · A graph: nodes and edges
graph = {
"A": ["B", "C"], "B": ["A", "D", "E"],
"C": ["A", "F"], "D": ["B", "G"],
"E": ["B", "G"], "F": ["C", "G"],
"G": ["D", "E", "F"],
}
>>> graph["B"] # B's neighbours
['A', 'D', 'E']
A Python set has no order. The drawing lists the seen set in the order nodes were added, to make it easy to follow. Both searches try neighbours in alphabetical order. A different order gives a different but equally valid visit order; BFS distances stay the same.