图的遍历(拓扑、DFS和BFS)

图的遍历是指从图中的某一个顶点出发,按照某种搜索方法沿着图中的边对图中的所有顶点访问一次且仅访问一次。注意到树是一种特殊的图,所以树的遍历实际上也可以看作是一种特殊的图的遍历。图的遍历主要有两种算法:广度优先搜索(Breadth-First-Search)和深度优先搜索(Depth-First-Search)。

深度优先搜索算法所遵循的搜索策略是尽可能“深”地搜索一个图。它的基本思想就是:首先访问图中某一起始顶点v,然后由v出发,访问与v邻接且未被访问的任一顶点w1,再访问与w1邻接且未被访问的任一顶点w2,……重复上述过程。当不能再继续向下访问时,依次退回到最近被访问的顶点,若它还有邻接顶点未被访问过,则从该点开始继续上述搜索过程,直到图中所有顶点均被访问过为止。使用递归来实现(https://www.zhihu.com/question/20507130)

广度优先搜索类似于二叉树的层序遍历,它的基本思想就是:首先访问起始顶点v,接着由v出发,依次访问v的各个未访问过的邻接顶点w1,w2,…,wi,然后再依次访问w1,w2,…,wi的所有未被访问过的邻接顶点;再从这些访问过的顶点出发,再访问它们所有未被访问过的邻接顶点……依次类推,直到图中所有顶点都被访问过为止。
广度优先搜索是一种分层的查找过程,每向前走一步可能访问一批顶点,不像深度优先搜索那样有往回退的情况,因此它不是一个递归的算法。为了实现逐层的访问,算法必须借助一个辅助队列,以记录正在访问的顶点的下一层顶点。

图的遍历(拓扑、DFS和BFS)_第1张图片

图的遍历(拓扑、DFS和BFS)_第2张图片

DFS : 2 0 1 3
BFS : 2 0 3 1

在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。且该序列必须满足下面两个条件:
1.每个顶点出现且只出现一次。
2.若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。
有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说。

它是一个 DAG 图,那么如何写出它的拓扑排序呢?这里说一种比较常用的方法:
1.从 DAG 图中选择一个 没有前驱(即入度为0)的顶点并输出。
2.从图中删除该顶点和所有以它为起点的有向边。
3.重复 1 和 2 直到当前的 DAG 图为空或当前图中不存在无前驱的顶点为止。后一种情况说明有向图中必然存在环。
可以使用在工期排序、大小关系排列、选课时的先修课(即要先修某某课才能学这一门课,先学了C语言再学数据结构这样)等情况。


图的遍历(拓扑、DFS和BFS)_第3张图片
拓扑排序

内容来自(http://blog.csdn.net/lisonglisonglisong/article/details/45543451)

#include 
#include 
#include 
#include 
using namespace std;
class Graph
{
    int V;                       //结点数目
    list *adj;              //邻接矩阵
    int* inDegree;               //入度数组
    queue q;                //入度为0的队列
    void BFSUtil(int v, bool visited[]);       //内部接口
    void DFSUtil(int v, bool visited[]);
public:
    Graph(int v);
    ~Graph();
    void addEdge(int v, int w);
    bool topoSort();
    void DFS(int v);            //外部接口
    void BFS(int v);           
};
Graph::Graph(int v)
{
    this->V = v;
    adj = new list[v];
    inDegree = new int[v];
    for(int i = 0; i < v; i++)      //新生成的图每个节点的入度都为0
       inDegree[i] = 0;
}
Graph::~Graph()
{
    delete [] adj;
    delete [] inDegree;
}
void Graph::addEdge(int v, int w)        //点v w相连接
{
    adj[v].push_back(w);
    inDegree[w]++;
}
bool Graph::topoSort()
{
    for(int i = 0; i < V; i++)
        if(inDegree[i]==0)
            q.push(i);
    int cnt = 0, v;               //cnt统计遍历节点数目 v记录此时遍历节点
    while(!q.empty())
    {
        v = q.front();
        q.pop();
        printf("%d ",v);
        cnt++;
        for(list::iterator i=adj[v].begin(); i!=adj[v].end(); i++)
            if(!(--inDegree[*i]))
                q.push(*i);
    }
    if(cnt == V)
        return true;
    else
        return false;
}
void Graph::BFSUtil(int v, bool visited[])
{
    queue que;
    visited[v] = true;
    que.push(v);
    int node;                   //出队元素
    while(!que.empty())
    {
        node = que.front();
        printf("%d ",node);
        que.pop();
        for(list::iterator i = adj[node].begin(); i != adj[node].end(); ++i)
            if(!visited[*i])
            {
                visited[*i] = true;
                que.push(*i);
            }
    }
}
void Graph::BFS(int v)
{
    bool *visited = new bool[V];
    for(int i = 0; i < V; i++)
        visited[i] = false;
    BFSUtil(v, visited);
}
void Graph::DFSUtil(int v, bool visited[])
{
    visited[v] = true;
    printf("%d ",v);
    for(list::iterator i = adj[v].begin(); i != adj[v].end(); ++i)
        if(!visited[*i])
        {
            visited[*i] = true;
            DFSUtil(*i, visited);
        }
}
void Graph::DFS(int v)
{
    bool *visited = new bool[V];
    for(int i = 0; i < V; i++)
        visited[i] = false;
    DFSUtil(v, visited);
}
int main()
{
    Graph g(4);
    g.addEdge(0,1);
    g.addEdge(0,2);
    g.addEdge(1,2);
    g.addEdge(2,0);
    g.addEdge(2,3);
    g.addEdge(3,3);

   // g.topoSort();

    g.BFS(2);
    printf("\n");
    g.DFS(2);

    return 0;
}

你可能感兴趣的:(图的遍历(拓扑、DFS和BFS))