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)的更多相关文章

  1. 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. ...

  2. [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 ...

  3. BFS 、DFS 解决迷宫入门问题

    问题 B: 逃离迷宫二 时间限制: 1 Sec  内存限制: 128 MB提交: 12  解决: 5[提交][状态][讨论版] 题目描述 王子深爱着公主.但是一天,公主被妖怪抓走了,并且被关到了迷宫. ...

  4. BFS和DFS详解

    BFS和DFS详解以及java实现 前言 图在算法世界中的重要地位是不言而喻的,曾经看到一篇Google的工程师写的一篇<Get that job at Google!>文章中说到面试官问 ...

  5. 【数据结构与算法】自己动手实现图的BFS和DFS(附完整源码)

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/19617187 图的存储结构 本文的重点在于图的深度优先搜索(DFS)和广度优先搜索(BFS ...

  6. BFS与DFS常考算法整理

    BFS与DFS常考算法整理 Preface BFS(Breath-First Search,广度优先搜索)与DFS(Depth-First Search,深度优先搜索)是两种针对树与图数据结构的遍历或 ...

  7. HDU-4607 Park Visit bfs | DP | dfs

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4607 首先考虑找一条最长链长度k,如果m<=k+1,那么答案就是m.如果m>k+1,那么最 ...

  8. 算法录 之 BFS和DFS

    说一下BFS和DFS,这是个比较重要的概念,是很多很多算法的基础. 不过在说这个之前需要先说一下图和树,当然这里的图不是自拍的图片了,树也不是能结苹果的树了.这里要说的是图论和数学里面的概念. 以上概 ...

  9. 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 ...

随机推荐

  1. Repository与UnitOfWork引入

    Repository是什么? 马丁大叔的书上同样也有解释:它是衔接数据映射层和域之间的一个纽带,作用相当于一个在内存中的域对象映射集合,它分离了领域对象和数据库访问代码的细 节.Repository受 ...

  2. unity3d常用控件

    直接上代码,就能看懂了. private string txt1; private string pwd1; private int tool1; private bool isMuted; priv ...

  3. javascript常量的定义

    例如可以使用 const PI = 3.14159265; 一般不推荐使用 const 关键字,因为它不是 ECMAScript 语法的一部分.当需要常量的时候一般是以命名习惯来约束的,亦即使用大写字 ...

  4. geopandas python地图绘制

    #geopandas python地理数据处理 瓦片地图:瓦片地图金字塔模型是一种多分辨率层次模型,从瓦片金字塔的底层到顶层,分辨率越来越低,但表示的地理范围不变.首先确定地图服务平台所要提供的缩放级 ...

  5. 2012全球SEO行业调查报告

    这份报告是SEOmoz对每两年一度举办的SEO行业调查进行的分析数据,上次调查是在2010年.该调查,主要围绕SEO从业人员的特征.工作内容时间分配比例.SEO相关消费和预算.对未来市场的看法.seo ...

  6. C语言之文件操作08——总结

    C程序的文件操作共涵盖7个例题,包括格式打印,文件读取,条件查找,矩阵的文件操作,数据格式输入及调用计算等内容. 文件操作使得程序有更强的拓展性,使其能够单独保存数据.这为程序的调试和优化打下了坚实的 ...

  7. 解决国内gem不能用的问题

    转自:http://www.haorooms.com/post/gem_not_use 最近在安装SASS的时候,用到gem命令,但是运行出行如下错误! C:\Users\len>gem ins ...

  8. [Egret]长按截屏分享、分享截屏图片、本地存储

    egret 分享有API可以把一个显示对象树渲染成一个位图纹理,我把它赋值给 HTML 的 Image 元素,就实现了图片的显示,在微信中,通过长按图片可以分享出去.当然在其他浏览器可以保存在本地. ...

  9. 分享 stormzhang的Andoid学习之路

    硬件 电脑–推荐Mac 首先声明我不是果粉,个人Windows,Linux,Mac OX系统均用过, 只能说Windows上面的开发工具简直难以恭维,尤其命令行超级难用,而Linux自己必须得花不少时 ...

  10. Qt之模式、非模式对话框

    关于“模式”和“非模式”对话框,相信大家都比较熟悉,但其中有一个可能很多人都比较陌生,介于两者之间的状态,我们称之为“半模式“. 模式对话框 描述 阻塞同一应用程序中其它可视窗口输入的对话框.模式对话 ...