[Algorithms] Graph Traversal (BFS and DFS)
Graph is an important data structure and has many important applications. Moreover, grach traversal is key to many graph algorithms. There are two systematic ways to traverse a graph, breadth-first search (BFS) and depth-frist search (DFS).
Before focusing on graph traversal, we first determine how to represent a graph. In fact, there are mainly two ways to represent a graph, either using adjacency lists or adjacency matrix.
An adjacency list is an array of lists. Each list corresponds to a node of the graph and stores the neighbors of that node.

For example, for the (undirected) graph above, its representation using adjacency lists can be:
0: 1 -> 3 -> NULL
1: 0 -> 2 -> NULL
2: 1 -> NULL
3: 0 -> 4 -> 5 -> NULL
4: 3 -> 5 -> 6 -> NULL
5: 3 -> 4 -> 6 -> 7 -> NULL
6: 4 -> 5 -> 7 -> NULL
7: 5 -> 6 -> NULL
An adjacency matrix is a matrix of size m by m (m is the number of nodes in the graph) and the (i, j)-the element of the matrix represents the edge from node i to node j.
For the same graph above, its representation using adjacency matrix is:
0 1 0 1 0 0 0 0
1 0 1 0 0 0 0 0
0 1 0 0 0 0 0 0
1 0 0 0 1 1 0 0
0 0 0 1 0 1 1 0
0 0 0 1 1 0 1 1
0 0 0 0 1 1 0 1
0 0 0 0 0 1 1 0
In this passage, we use adjacency lists to represent a graph. Specifically, we define the node of the graph to be the following structure:
struct GraphNode {
int label;
vector<GraphNode*> neighbors;
GraphNode(int _label) : label(_label) {}
};
Now let's move on to BFS and DFS.
As suggested by their names, BFS will first visit the current node, then its neighbors, then the non-visited neighbors of its neighbors... and so on in a breadth-first manner while DFS will try to move as far as possible from the current node and backtrack when it cannot move forward any more (all the neighbors of the current node has been visited).
The implementation of BFS requries the use of the queue data structure while the implementation of DFS can be done in a recursive manner.
For more details on BFS and DFS, you may refer to Introduction to Algorithms or these two nice videos: BFS video and DFS video.
In my implementation, BFS starts from a single node and visits all the nodes reachable from it and returns a sequence of visited nodes. However, DFS will try to start from every non-visited node in the graph and starts from that node and obtains a sequence of visited nodes for each starting node. Consequently, the function bfs returns a vector<GraphNode*> while the function dfs returns a vector<vector<GraphNode*> >.
I also implement a function read_graph to input the graph manually. For the above graph, you first need to input its number of nodes and number of edges. Then you will input each of its edge in the form of "0 1" (edge from node 0 to node 1).
The final code is as follows.
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_set> using namespace std; struct GraphNode {
int label;
vector<GraphNode*> neighbors;
GraphNode(int _label) : label(_label) {}
}; vector<GraphNode*> read_graph(void) {
int num_nodes, num_edges;
scanf("%d %d", &num_nodes, &num_edges);
vector<GraphNode*> graph(num_nodes);
for (int i = ; i < num_nodes; i++)
graph[i] = new GraphNode(i);
int node, neigh;
for (int i = ; i < num_edges; i++) {
scanf("%d %d", &node, &neigh);
graph[node] -> neighbors.push_back(graph[neigh]);
graph[neigh] -> neighbors.push_back(graph[node]);
}
return graph;
} vector<GraphNode*> bfs(vector<GraphNode*>& graph, GraphNode* start) {
vector<GraphNode*> nodes;
queue<GraphNode*> toVisit;
unordered_set<GraphNode*> visited;
toVisit.push(start);
visited.insert(start);
while (!toVisit.empty()) {
GraphNode* cur = toVisit.front();
toVisit.pop();
nodes.push_back(cur);
for (GraphNode* neigh : cur -> neighbors) {
if (visited.find(neigh) == visited.end()) {
toVisit.push(neigh);
visited.insert(neigh);
}
}
}
return nodes;
} bool visitAllNeighbors(GraphNode* node, unordered_set<GraphNode*>& visited) {
for (GraphNode* n : node -> neighbors)
if (visited.find(n) == visited.end())
return false;
return true;
} void dfs_visit(vector<GraphNode*>& graph, GraphNode* node, \
unordered_set<GraphNode*>& visited, vector<GraphNode*>& tree, \
vector<vector<GraphNode*> >& forest) {
visited.insert(node);
tree.push_back(node);
if (visitAllNeighbors(node, visited)) {
forest.push_back(tree);
tree.clear();
return;
}
for (GraphNode* neigh : node -> neighbors)
if (visited.find(neigh) == visited.end())
dfs_visit(graph, neigh, visited, tree, forest);
} vector<vector<GraphNode*> > dfs(vector<GraphNode*>& graph) {
vector<GraphNode*> tree;
vector<vector<GraphNode*> > forest;
unordered_set<GraphNode*> visited;
for (GraphNode* node : graph)
if (visited.find(node) == visited.end())
dfs_visit(graph, node, visited, tree, forest);
return forest;
} void graph_test(void) {
vector<GraphNode*> graph = read_graph();
// BFS
printf("BFS:\n");
vector<GraphNode*> nodes = bfs(graph, graph[]);
for (GraphNode* node : nodes)
printf("%d ", node -> label);
printf("\n");
// DFS
printf("DFS:\n");
vector<vector<GraphNode*> > forest = dfs(graph);
for (vector<GraphNode*> tree : forest) {
for (GraphNode* node : tree)
printf("%d ", node -> label);
printf("\n");
}
} int main(void) {
graph_test();
system("pause");
return ;
}
If you input the above graph to it as follows (note that you only need to input each edge exactly once):
The output will be as follows:
BFS: DFS:
You may check it manually and convince yourself of its correctness :)
[Algorithms] Graph Traversal (BFS and DFS)的更多相关文章
- Clone Graph leetcode java(DFS and BFS 基础)
题目: Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. ...
- [LeetCode] 785. Is Graph Bipartite?_Medium tag: DFS, BFS
Given an undirected graph, return true if and only if it is bipartite. Recall that a graph is bipart ...
- BFS 、DFS 解决迷宫入门问题
问题 B: 逃离迷宫二 时间限制: 1 Sec 内存限制: 128 MB提交: 12 解决: 5[提交][状态][讨论版] 题目描述 王子深爱着公主.但是一天,公主被妖怪抓走了,并且被关到了迷宫. ...
- BFS和DFS详解
BFS和DFS详解以及java实现 前言 图在算法世界中的重要地位是不言而喻的,曾经看到一篇Google的工程师写的一篇<Get that job at Google!>文章中说到面试官问 ...
- 【数据结构与算法】自己动手实现图的BFS和DFS(附完整源码)
转载请注明出处:http://blog.csdn.net/ns_code/article/details/19617187 图的存储结构 本文的重点在于图的深度优先搜索(DFS)和广度优先搜索(BFS ...
- BFS与DFS常考算法整理
BFS与DFS常考算法整理 Preface BFS(Breath-First Search,广度优先搜索)与DFS(Depth-First Search,深度优先搜索)是两种针对树与图数据结构的遍历或 ...
- HDU-4607 Park Visit bfs | DP | dfs
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4607 首先考虑找一条最长链长度k,如果m<=k+1,那么答案就是m.如果m>k+1,那么最 ...
- 算法录 之 BFS和DFS
说一下BFS和DFS,这是个比较重要的概念,是很多很多算法的基础. 不过在说这个之前需要先说一下图和树,当然这里的图不是自拍的图片了,树也不是能结苹果的树了.这里要说的是图论和数学里面的概念. 以上概 ...
- hdu--1026--Ignatius and the Princess I(bfs搜索+dfs(打印路径))
Ignatius and the Princess I Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (J ...
随机推荐
- applicationCache
<html manifest="/m.appcache"> window.applicationCache.onupdateready = function (e) { ...
- Java编程介绍
原文地址:http://happyshome.cn/blog/java/introduction.html 本文介绍的编程基础知识很Java适合刚開始学习的人. 要学习编程,你须要了解编程语言的语法和 ...
- Atitti. 语法树AST、后缀表达式、DAG、三地址代码
Atitti. 语法树AST.后缀表达式.DAG.三地址代码 抽象语法树的观点认为任何复杂的语句嵌套情况都可以借助于树的形式加以描述.确实,不得不承认应用抽象语法树可以使语句翻译变得相对容易,它很好地 ...
- SVN提交项目时版本冲突解决方案
版本冲突原因: 假设A.B两个用户都在版本号为7的时候,更新了index.jsp这个文件,A用户在修改完成之后提交index.jsp到服务器,这个时候提交成功,这个时候index.jsp文件的版本号已 ...
- vue天坑系列
vue运行四元素:main.js+router/index.js+index.html+App.vue缺一不可:
- mysql替换成指定字符
,,, ), 'XXXX' )-- 隐藏从第四位开始的6个字符,包括第四个字符,替换成X
- OSI七层模型与TCP/IP五层模型详解
博主是搞是个FPGA的,一直没有真正的研究过以太网相关的技术,现在终于能静下心学习一下,希望自己能更深入的掌握这项最基本的通信接口技术.下面就开始搞了. 一.OSI参考模型 今天我 ...
- debian下为arm开发板创建基于debian或emdebian的根文件系统
Debian系统本身包含对arm的支持,其包含的软件包最多,但是最终的文件系统要大一些. emdebian 是一个非常好用的嵌入式linux操作系统,其基于debian的特点对于熟悉debian系统的 ...
- 通用采集器Modbus协议应用
1. 功能码 通用采集器一般包含DI,DO,AI相关接口,对此类接口主要应用功能码01~06. 3类接口具体对应关系如下: 继电器定义,功能码01/05(01:读线圈,05写线圈) 序号 ...
- CentOS下搭建wordpress全流程
突然,想搭建一个个人博客,所以就在网上搜了搜相关内容,好多人推荐wordpress,那么就打算光荣地采用wordpress了.以下是安装过程中遇到的所有的坑,现在总结如下,希望给安装wordpress ...