图的遍历-深搜(DFS)和广搜(BFS)

最近为了保研在复习数据结构和算法,想来可以用博客记录一些,以后或许能用的上。

首先说一下图的定义。

图是一种数据结构,图和树一样可以用二元组表示。它可定义为Graph=(V,R)其中,V={x|x∈datatype},R={VR},VR={(x,y)|P(x,y)∧(x,y∈V)}。在图中,数据元素常称为顶点(Vertex),V是顶点的非空有穷集合;R是边(弧)的有穷集合。

也就是说,图就是记录一些点和点之间的关系的数据结构。

图的存储大致分为两类,因为主要想说的是遍历,所以大概说一下存储。

  1. 邻接矩阵
    邻接矩阵就是一个二维数组,不同的下标对应着不同的结点。而如果是无向图,vi<->vj 即 graph[vi][vj] = graph[vj][vi] = 1; 有向图 vi->vj 则只有graph[vi][vj] = 1。如果边上有权重val,则graph[vi][vj] = val。
    而虽然邻接矩阵在记录边关系时很方便,但是面临的问题是浪费大量空间,特别是面对稀疏图(即图中边的数量大大少于节点数量)时,问题尤其明显。因为我们的示例图很简单,所以接下来我用的都是邻接矩阵。
  2. 邻接表
    邻接表的出现解决了邻接矩阵的问题,即使用了链式结构。 邻接表的处理方法是这样的:
    • 图中顶点用一个一维数组存储。
    • 图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以,用链表存储。链表中每个节点有两个信息:当前顶点的下标,指向下一节点的指针。在该图中,数组里面的下标对应不同的顶点,而链表里的节点对应这个顶点的邻接点。
      《图的遍历-深搜(DFS)和广搜(BFS)》

接下来是本文的主要点:图的遍历。

《图的遍历-深搜(DFS)和广搜(BFS)》

上面是一个无向图的示例图。

  1. 深度优先搜索(DFS)
    由这个名字我们就能知道,DFS注重的是深度优先。即走一条路走到底,走不动了回来看有没有岔路口,有的话接着走到底。当然已经走过的地方不能再走一遍了。拿上图举例,我们从v1出发,如果我们先走左边的顶点(这个左边在程序里即第一个顶点),我们走到了v2,发现还能往下(下的意思是有邻接点存在)走,走左边到了v4,发现有岔路口,但是v1我们走过了,只能走v5,v5走到了v3。此时全部点都遍历了一遍,即DFS完成。顺序:v1,v2,v4,v5,v3。
  2. 广度优先搜索(BFS)
    BFS注重的是广度,按层次遍历。即先把眼前的地方先走一遍,再接着遍历更远的地方。拿上图举例。我们从v1出发,首先把眼前的顶点遍历完(即遍历v1所有的邻接点),我们遍历了v2,v3,v4。然后从最左边的顶点接着重复此过程,遍历了v5。此时全部点都遍历了一遍,即BFS完成。顺序:v1,v2,v3,v4,v5。
    我们可以看出来,BFS和DFS的时间复杂度相同,不同的只有遍历顶点的顺序不同而已。所以我们根据不同的情况使用不同的遍历方法即可。

下面是创建邻接矩阵图,DFS和BFS的代码:

#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
#define MAX 100
#define max(x,y)(x>y?x:y)
#define initNode 1 //这里我们假设遍历从顶点1开始,也可以改成其他的
typedef struct{
    int matrix[MAX][MAX]; //邻接矩阵
    int num;// 最大的顶点数
}Graph;

Graph example; //实例图

// 创建图
void createPoint(){
    int i,j;
    memset(example.matrix,0,sizeof(example.matrix));
    example.num=0;
    while(cin>>i>>j&&i!=0 && j!=0){
        example.matrix[i][j]=1;
        example.matrix[j][i]=1;
        example.num = max(example.num,i);
        example.num = max(example.num,j);
    }
}
// DFS 函数主体 用递归实现
void DFS(int x,int * visited){
    cout<<" "<<x;
    for(int i=1;i<=example.num;i++){
        if(visited[i]==0 && example.matrix[x][i]==1){
            visited[i]=1;
            DFS(i,visited);
        }
    }
}
// DFS DFS初始化
void initDFS(){
    int *visited = new int[example.num++];
    memset(visited,0,sizeof(int)*(example.num+1));
    cout<<"DFS"<<"------------------------------------"<<endl;
    visited[initNode]=1;
    DFS(initNode,visited);

    cout<<endl<<"DFS"<<"------------------------------------"<<endl;
}

// BFS 用队列实现该功能 
void BFS(){
    int i,nNode;
    queue<int> gQueue;
    int *visited = new int[example.num++];
    memset(visited,0,sizeof(int)*(example.num+1));

    cout<<"BFS"<<"------------------------------------"<<endl;
    visited[initNode]=1;
    gQueue.push(initNode);

    while(!gQueue.empty()){
        nNode = gQueue.front();
        cout<<" "<<nNode;
        for(i=1;i<=example.num;i++){
            if(example.matrix[nNode][i]==1 && visited[i]==0){ 
                    gQueue.push(i);
                    visited[i]=1;
            }
        }
        gQueue.pop();
    }
    cout<<endl<<"BFS"<<"------------------------------------"<<endl;
}

int main(){
    createPoint();
    BFS();
    initDFS();
    return 0;
}

输出结果(输入的形式是以邻接点对的形式,以0 0结束):

1 2
1 4
1 3
2 4
2 5
3 5
4 5
0 0
BFS------------------------------------
 1 2 3 4 5
BFS------------------------------------
DFS------------------------------------
 1 2 4 5 3
DFS------------------------------------
    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/u010006643/article/details/45673571
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞