算法导论--图的遍历(DFS与BFS)

转载请注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51897538



图的遍历就是从图中的某个顶点出发,按某种方法对图中的所有顶点访问且仅访问一次。为了保证图中的顶点在遍历过程中仅访问一次,要为每一个顶点设置一个访问标志。通常有两种方法:深度优先搜索(DFS)和广度优先搜索(BFS).这两种算法对有向图与无向图均适用。

以下面无向图为例:

1.深度优先搜索(DFS)

基本步骤:

1.从图中某个顶点v0出发,首先访问v0;

2.访问结点v0的第一个邻接点,以这个邻接点vt作为一个新节点,访问vt所有邻接点。直到以vt出发的所有节点都被访问到,回溯到v0的下一个未被访问过的邻接点,以这个邻结点为新节点,重复上述步骤。直到图中所有与v0相通的所有节点都被访问到。

3.若此时图中仍有未被访问的结点,则另选图中的一个未被访问的顶点作为起始点。重复深度优先搜索过程,直到图中的所有节点均被访问过。

DFS遍历结果:A,B,C,F,E,G,D,H,I


2.广度优先搜索(BFS)

2.1 BFS类似与树的层次遍历,从源顶点s出发,依照层次结构,逐层访问其他结点。即访问到距离顶点s为k的所有节点之后,才会继续访问距离为k+1的其他结点。

基本步骤:

1.从图中某个顶点v0出发,首先访问v0;

2.依次访问v0的各个未被访问的邻接点。

3.依次从上述邻接点出发,访问他们的各个未被访问的邻接点。始终保证一点:如果vi在vk之前被访问,则vi的邻接点应在vk的邻接点之前被访问。重复上述步骤,直到所有顶点都被访问到。

4.如果还有顶点未被访问到,则随机选择一个作为起始点,重复上述过程,直到图中所有顶点都被访问到。

BFS遍历结果:A,B,D,E,C,G,F,H,I

为了按照优先访问顶点的次序,访问其邻接点,所以需要建立一个优先队列(先进先出)。

2.2 采用此算法还可以很方便计算距离任一顶点vi的路径长度为k的所有顶点;从顶点vi出发进行广度优先搜索,可以记录到每一步,两步,…,k步可到达的顶点。采用一个距离队列与访问队列同步,距离队列是访问队列中对应顶点距离vi的距离。例如距离顶点B为2的顶点为D、F、G.


3.完整代码

/************************************************************************
CSDN 勿在浮沙筑高台 http://blog.csdn.net/luoshixian099算法导论--图的遍历2016年7月13日
************************************************************************/
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
char vextex[] = { ‘A‘, ‘B‘, ‘C‘, ‘D‘, ‘E‘, ‘F‘, ‘G‘, ‘H‘, ‘I‘ };
typedef struct VertexNode  //链表表头结点
{
    char data;
    struct ArcNode * firstarc;
}VertexNode;
typedef struct ArcNode  //弧结点
{
    char data;
    struct ArcNode * nextarc;
}ArcNode;
ArcNode * InSertArcNode(char name)
{
    ArcNode * p = new ArcNode;
    p->data = name;
    p->nextarc = NULL;
    return p;
}
VertexNode * AdjList()//邻接链表表示法
{
    ArcNode * p=NULL;
    VertexNode * List_head = new VertexNode[9];
    int count = 0;
    List_head[count].data = ‘A‘;
    p = List_head[count].firstarc = InSertArcNode(‘B‘);
    p = p->nextarc = InSertArcNode(‘D‘);
    p = p->nextarc = InSertArcNode(‘E‘);
    count++;
    List_head[count].data = ‘B‘;
    p = List_head[count].firstarc = InSertArcNode(‘A‘);
    p = p->nextarc = InSertArcNode(‘C‘);
    p = p->nextarc = InSertArcNode(‘E‘);
    count++;
    List_head[count].data = ‘C‘;
    p = List_head[count].firstarc = InSertArcNode(‘B‘);
    p = p->nextarc = InSertArcNode(‘F‘);
    count++;
    List_head[count].data = ‘D‘;
    p = List_head[count].firstarc = InSertArcNode(‘A‘);
    p = p->nextarc = InSertArcNode(‘G‘);
    count++;
    List_head[count].data = ‘E‘;
    p = List_head[count].firstarc = InSertArcNode(‘A‘);
    p = p->nextarc = InSertArcNode(‘B‘);
    p = p->nextarc = InSertArcNode(‘G‘);
    count++;
    List_head[count].data = ‘F‘;
    p = List_head[count].firstarc = InSertArcNode(‘C‘);
    count++;
    List_head[count].data = ‘G‘;
    p = List_head[count].firstarc = InSertArcNode(‘D‘);
    p = p->nextarc = InSertArcNode(‘E‘);
    p = p->nextarc = InSertArcNode(‘H‘);
    count++;
    List_head[count].data = ‘H‘;
    p = List_head[count].firstarc = InSertArcNode(‘G‘);
    p = p->nextarc = InSertArcNode(‘I‘);
    count++;
    List_head[count].data = ‘I‘;
    p = List_head[count].firstarc = InSertArcNode(‘H‘);

    return List_head;
}

void AdjMatrix(char arc[][9])
{
    for (int i = 0; i < 9; i++)   //初始化邻接矩阵
        for (int j = 0; j < 9; j++)
        {
            arc[i][j] = 0;
        }
    arc[0][1] = arc[0][3] = arc[0][4] = 1;
    arc[1][0] = arc[1][2] = arc[1][4] = 1;
    arc[2][1] = arc[2][5] = 1;
    arc[3][0] = arc[3][6] = 1;
    arc[4][0] = arc[4][1] = arc[4][6] = 1;
    arc[5][2] = 1;
    arc[6][3] = arc[6][4] = arc[6][7] = 1;
    arc[7][6] = arc[7][8] = 1;
    arc[8][7] = 1;
}
void DFS_matrix(char G[][9],int i,bool *visited)  //深度优先搜索与结点i相通的所有节点
{
    visited[i] = true;  //顶点i被访问,标志置为true
    for (int j = 0; j < 9; j++)
    {
        if (!visited[j] && G[i][j]==1)
        {
            cout << vextex[j] << ",";
            DFS_matrix(G, j, visited); //递归
        }
    }
}
void DFS_AdjMatrix(char G[][9])  //深度优先搜索_邻近矩阵存储
{
    bool visited[9] = { 0 };  //初始化访问标志数组
    for (int i = 0; i < 9; i++) //检测是否所有节点都被访问过
    {
        if (!visited[i])//顶点i未被访问过,结点i进行深度优先搜索
        {
            cout << vextex[i]<<",";
            DFS_matrix(G, i, visited);//深度优先搜索顶点i
        }
    }
}
void DFS_list(VertexNode * GRAPH, int i, bool *visited)
{
    visited[i] = true;  //顶点i被访问,标志置为true
    cout << vextex[i] << ",";
    ArcNode * p = GRAPH[i].firstarc; //找到第一个邻接链表结点
    while (p!=NULL)
    {
        int temp = p->data - ‘A‘; //计算节点的位置
        if (!visited[temp]) //检测邻接顶点是否被访问过
            DFS_list(GRAPH, temp, visited); //深度优先搜索结点temp
        p = p->nextarc;//回溯到下一个邻接顶点
    }
}
void DFS_AdjList(VertexNode * GRAPH)  //深度优先搜索--邻接链表存储
{
    bool visited[9] = { 0 }; //初始化访问标志数组
    for (int i = 0; i < 9; i++)//检测是否所有节点都被访问过
    {
        if (!visited[i])
        {
            DFS_list(GRAPH, i, visited);//深度优先搜索顶点i
        }
    }
}
void BFS_list(VertexNode *GRAPH, int i, bool *visited, queue<char> &Q)
{
    cout << Q.front() << ",";
    Q.pop(); //出队列
    /*访问到顶点i的所有邻接点*/
    ArcNode *p = GRAPH[i].firstarc; //第一个邻结点
    while ( p!=NULL )  //依次访问顶点i的邻接点
    {
        /*(p->data - ‘A‘)代表顶点的序号*/
        if (*(visited + (p->data - ‘A‘)) == 0)//检测邻接点是否被访问过
        {
            *(visited + (p->data - ‘A‘)) = true;//访问标志置1
            Q.push(p->data); //邻接点加入优先队列
        }
        p = p->nextarc;
    }
    if (!Q.empty()) //递归遍历队列里的顶点
    {
        BFS_list(GRAPH, Q.front() - ‘A‘, visited, Q);
    }
}
void BFS_AdjList(VertexNode *GRAPH)//广度优先搜索顶点i--邻接表存储
{
    bool visited[9] = { 0 }; //访问标志初始化
    queue<char> Q; //优先队列
    for (int i = 0; i < 9; i++)
    {
        if (!visited[i])
        {
            visited[i] = true;  //访问标志置1
            Q.push(vextex[i]);   //进入顶点队列
            BFS_list(GRAPH, i, visited, Q); //广度优先搜索顶点i
        }
    }
}
void BFS_KLevel(VertexNode * GRAPH, int i,int k) //计算距离顶点i为k的所有顶点
{
    if (k==0) //如果k=0,输出此顶点
    {
        cout << GRAPH[i].data << endl;
        return;
    }
    queue<char> Q1; //已访问顶点
    queue<unsigned int> Q2; //已访问顶点与顶点i的距离
    bool visited[9] = { 0 };//访问标志
    visited[i] = true;   //顶点i置1
    Q1.push(vextex[i]); //进入队列
    Q2.push(0);  //距离队列

    while (!Q1.empty())
    {
        int index = Q1.front() - ‘A‘;  //顶点的序号

        ArcNode *p = GRAPH[index].firstarc;//第一个邻接点
        int level = Q2.front();
        while (p!=NULL)
        {
            if (*(visited+(p->data-‘A‘)) == 0)  //结点没有被访问过
            {
                *(visited + (p->data - ‘A‘)) =true;//访问标志置1
                Q1.push(p->data);
                Q2.push(level + 1);  //距离+1
                if (level + 1 == k)  //判断距离
                {
                    cout << p->data << ",";
                }
            }
            p = p->nextarc;
        }
        Q1.pop();
        Q2.pop();
    }

}

int main()
{   

    VertexNode * GRAPH = AdjList();  //邻接链表
    char G[9][9] = { 0 };
    AdjMatrix(G);   //邻接矩阵
    DFS_AdjMatrix(G); //DFS--邻接矩阵
    cout <<"  DFS--邻接矩阵"<< endl;
    DFS_AdjList(GRAPH); //DFS--邻接链表
    cout << "  DFS--邻接链表" << endl;
    BFS_AdjList(GRAPH); //BFS--邻接链表
    cout << "  BFS--邻接链表" << endl;
    cout << "------------" << endl;
    BFS_KLevel(GRAPH,1,2);//计算距离顶点B为2的顶点
    cout << " 距离顶点B为2的顶点" << endl;
    return 0;
}



Reference :

数据结构–耿国华

算法导论-第三版

时间: 2024-08-03 15:34:13

算法导论--图的遍历(DFS与BFS)的相关文章

图的遍历——DFS和BFS模板(一般的图)

关于图的遍历,通常有深度优先搜索(DFS)和广度优先搜索(BFS),本文结合一般的图结构(邻接矩阵和邻接表),给出两种遍历算法的模板 1.深度优先搜索(DFS) #include<iostream> #include<unordered_map> #include<queue> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #

图的遍历 DFS和BFS

深度优先搜索 (Depth First Search, DFS): void DFS ( Vertex V ) { visited[ V ] = true; for ( V 点 的每个邻接点 W ) if ( !visited[ W ] ) DFS( W ); } 若有N 个顶点.E 条边,时间复杂度是 用邻接表存储图,有O(N+E) 用邻接矩阵存储图,有O(N 2 ) 广度优先搜索 (Breadth First Search, BFS) void BFS ( Vertex V ) { visi

785. 判断二分图——本质上就是图的遍历 dfs或者bfs

785. 判断二分图 给定一个无向图graph,当这个图为二分图时返回true. 如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图. graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点.每个节点都是一个在0到graph.length-1之间的整数.这图中没有自环和平行边: graph[i] 中不存在i,并且graph[i]中没有重复的值. 示例 1: 输入: [[1,3], [

图的遍历(DFS、BFS)

理论: 深度优先搜索(Depth_Fisrst Search)遍历类似于树的先根遍历,是树的先根遍历的推广: 广度优先搜索(Breadth_First Search) 遍历类似于树的按层次遍历的过程: java实现 Vertex.java package 图; public class Vertex{ String value; boolean isVisited; Vertex(String value) { this.value=value; this.isVisited=false; }

算法导论--图的存储(邻接表与邻接矩阵)

转载请注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51888031 图的存储方法有邻接表.邻近矩阵.邻接多重表.十字链表等.本篇文章介绍两种简单且比较常用的两种方法:邻接表与邻接矩阵方法. 以下面的无向图为例,介绍两种存储方法.有向图的存储方法类似,只是边是单方向,无向图的边可以看做双向. 1.邻接链表法 邻接链表表示法对图中的每个顶点建立一个带头的边链表:第i条链表代表依附于顶点vi所有边信息,若为有向图,则表示

算法导论—无向图的遍历(BFS+DFS,MATLAB)

华电北风吹 天津大学认知计算与应用重点实验室 最后改动日期:2015/8/22 无向图的存储方式有邻接矩阵,邻接链表,稀疏矩阵等. 无向图主要包括双方面内容,图的遍历和寻找联通分量. 一.无向图的遍历 无向图的遍历有两种方式-广度优先搜索(BFS)和深度优先搜索(DFS).广度优先搜索在遍历一个顶点的全部节点时,先把当前节点全部相邻节点遍历了.然后遍历当前节点第一个相邻的节点的全部相邻节点,广度优先搜索使用队列来实现.深度优先搜索在遍历当前节点的全部相邻节点时,先对当前节点的第一个相邻节点进行訪

数据结构与算法10—图的遍历

图的遍历 1. 在图中有回路,从图中某一顶点出发访问图中其它顶点时,可能又会回到出发点,而图中可能还剩余有顶点没有访问到. 2. 我们可以设置一个全局型标志数组visited来标志某个顶点是否被访问过,未访问的值为0,访问过的值为1. 3. 图的遍历有两种方法:深度优先搜索遍历(DFS).广度优先搜索遍历(BFS). 深度优先搜索 深度优先搜索思想 首先访问顶点i,并将其访问标记置为访问过,即visited[i] =1: 然后搜索与顶点i有边相连的下一个顶点j,若j未被访问过,则访问它,并将j的

【算法导论】--C++实现广度优先搜索bfs

一.题目 根据上次随机生成的100个顶点的无向图和有向图,对其进行广度优先搜索. 二.理解广度优先搜索 广度优先搜索可以将其想象成水滴落入水面溅起了的一圈一圈的涟漪,是由一个起始点开始一圈一圈进行扩散搜索的. [课上老师是这样说的,大家想象一下,发现其实非常形象] 广度优先搜索总是从一个起始点出发,首先扩散这个点周围所有的邻居,然后邻居在去扩散邻居的邻居(*^-^*)...然后一直到最后将整张图都扩散完. 三.代码实现 对于第一次随机生成100个顶点的图进行了细节的修改,将每个顶点的类型改为了自

数据结构(15):图 深度优先遍历(DFS)

/*-----------------------------------------------*/ /* 邻接矩阵的DFS */ // 基于 数据结构(14) 中的邻接矩阵的结构 #include <iostream> using namespace std; typedef char VertexType; typedef int EdgeType; const int MAXVEX = 100; const int INFINITY = 65535; typedef struct {