关闭

[置顶] 图的遍历(上)——邻接矩阵表示

标签: 数据结构BFSDFS邻接矩阵
398人阅读 评论(0) 收藏 举报
分类:

概述

图作为数据结构书中较为复杂的数据结构,对于图的存储方式分邻接矩阵和邻接表两种方式。在这篇博客中,主要讲述邻接矩阵下的图的深度优先遍历(DFS)与广度优先遍历(BFS)。


广度优先遍历(BFS)

BFS 算法的思想是:对一个无向连通图,在访问图中某一起始顶点 v 后,由 v 出发,依次访问 v 的所有未访问过的邻接顶点 w1, w2, w3, …wt;然后再顺序访问 w1, w2, w3, …wt 的所有还未访问过的邻接顶点;再从这些访问过的顶点出发,再访问它们的所有还未访问过的邻接顶点,……,如此直到图中所有顶点都被访问到为止。
算法叙述:
1)首先初始化队列为空
2)把初始结点入队,并把对应访问数组isvisit元素置1,之后依次把其未被访问的邻接点入队,之后打印当前结点
3)用当前结点保存为出队元素,重复2)直至队列为空。

//广度优先遍历BFS 
void BFS(int vertex){
    queue<int> queue;
    queue.push(vertex);         //初始结点入队 
    this->isvisited[vertex] = 1;
    int now;
    while(!queue.empty()){      //队不空一直循环 
        now = queue.front();    //对头元素出栈    
        queue.pop();
        cout<<now<<" ";             //打印当前结点
        int i = 1;
        while(i <= this->Nv){       //与当前结点相邻且未被访问的结点入队 
            if(this->G[now][i] == 1 && isvisited[i] == 0){
                queue.push(i);
                this->isvisited[i] = 1; //访问数组相应的置1 
            }
            i++;
        }
    }
}

深度优先遍历(DFS)——递归版本

递归算法:
1)访问起点v0
2)依次以v0的未访问的连接点为起点,DFS搜索图,直至图中所有与v0路径相通的顶点都被访问。
3)若该图为非连通图,则图中一定还存在未被访问的顶点,选取该顶点为起点,重复上述DFS过程,直至图中全部顶点均被访问过为止。

//递归深度优先遍历DFS 
void DFS1(int vertex){
    cout<<vertex<<" ";                  //打印第一个结点 
    this->isvisited[vertex] = 1;        //相应位的访问数组置1 
    for(int i = 1 ; i <= this->Nv ; i++){
        //依次递归遍历当前结点的未被访问的邻接点 
        if(this->G[vertex][i] == 1 && this->isvisited[i] == 0){
            this->isvisited[i] = 0;
            this->DFS1(i);
            this->isvisited[i] = 0; 
        }
    }
    this->isvisited[vertex] = 0;
}

深度优先遍历(DFS)——非递归版本

非递归算法:
1)首先初始化待使用栈,然后将第一个结点入栈
2)然后只要栈不空,重复下面的操作:将栈顶元素弹出,然后看该元素是否访问过
3)若没访问过,则访问,置访问标记,然后将该元素的所有未被访问的相邻顶点入栈(注意是全部,所以应用一个for或while循环来判断哪些元素该入栈)
4)重复2,直至全部顶点均被访问过。

//非递归深度优先遍历DFS
void DFS2(int vertex){
    stack<int> stack;
    stack.push(vertex);             //当前结点入栈 
    this->isvisited[vertex] = 1;    //相应位的访问数组置1 
    int now;
    while(!stack.empty()){          //栈不空则一直循环 
        now = stack.top();          //当前结点出栈 
        stack.pop();
        cout<<now<<" ";             //打印当前结点
        //把当前结点的未被访问的邻接点依次入栈并把相应访问数组置1 
        for(int i = 1 ; i <= this->Nv ; i++){
            if(this->G[now][i] != 0 && this->isvisited[i] == 0){
                stack.push(i);
                this->isvisited[i] = 1;
            }
        } 
    }
} 

例子

下面的程序所基于的图结构够如下:
这里写图片描述
全部代码:

#include <iostream>
#include <cstring>
#include <queue>
#include <stack>
using namespace std;

class Graph{
    private:
        int** G;                //邻接矩阵 
        int* isvisited;         //访问数组 
        int Nv;                 //顶点数
        int Ne;                 //边数 
    public:
        //构造函数 
        Graph(int nv , int ne){
            this->Nv = nv;
            this->Ne = ne;
            this->G = new int*[nv+1];
            this->isvisited = new int[nv+1];
            memset(isvisited,0,sizeof(isvisited[0])*(nv+1));
            for(int i = 0 ; i < nv+1 ; i++){
                G[i] = new int[nv+1];
                memset(G[i],0,sizeof(G[i][0])*(nv+1));
            }
            cout<<"请输入边:"<<endl;
            for(int i = 0 ; i < ne ; i++){
                int a,b;
                cin>>a>>b;
                this->G[a][b] = 1;
                this->G[b][a] = 1;
            }
        }

        //重置函数
        void reset(){
            memset(this->isvisited,0,sizeof(this->isvisited[0])*(this->Nv+1));
        }

        //广度优先遍历BFS 
        void BFS(int vertex){
            queue<int> queue;
            queue.push(vertex);         //初始结点入队 
            this->isvisited[vertex] = 1;
            int now;
            while(!queue.empty()){      //队不空一直循环 
                now = queue.front();    //对头元素出栈    
                queue.pop();
                cout<<now<<" ";             //打印当前结点
                int i = 1;
                while(i <= this->Nv){       //与当前结点相邻且未被访问的结点入队 
                    if(this->G[now][i] == 1 && isvisited[i] == 0){
                        queue.push(i);
                        this->isvisited[i] = 1; //访问数组相应的置1 
                    }
                    i++;
                }
            }
        }

        //递归深度优先遍历DFS 
        void DFS1(int vertex){
            cout<<vertex<<" ";                  //打印第一个结点 
            this->isvisited[vertex] = 1;        //相应位的访问数组置1 
            for(int i = 1 ; i <= this->Nv ; i++){
                //依次递归遍历当前结点的未被访问的邻接点 
                if(this->G[vertex][i] == 1 && this->isvisited[i] == 0){
                    this->isvisited[i] = 0;
                    this->DFS1(i);
                    this->isvisited[i] = 0; 
                }
            }
            this->isvisited[vertex] = 0;
        }

        //非递归深度优先遍历DFS
        void DFS2(int vertex){
            stack<int> stack;
            stack.push(vertex);             //当前结点入栈 
            this->isvisited[vertex] = 1;    //相应位的访问数组置1 
            int now;
            while(!stack.empty()){          //栈不空则一直循环 
                now = stack.top();          //当前结点出栈 
                stack.pop();
                cout<<now<<" ";             //打印当前结点
                //把当前结点的未被访问的邻接点依次入栈并把相应访问数组置1 
                for(int i = 1 ; i <= this->Nv ; i++){
                    if(this->G[now][i] != 0 && this->isvisited[i] == 0){
                        stack.push(i);
                        this->isvisited[i] = 1;
                    }
                } 
            }
        } 
};

int main()
{
    cout<<"请输入结点总数与边数:"<<endl; 
    int nv,ne;
    cin>>nv>>ne;
    Graph graph(nv,ne);
    cout<<"请输入第一个访问的结点:"<<endl;
    int now;
    cin>>now;

    cout<<"广度优先遍历(BFS)序列为:"<<endl; 
    graph.BFS(now);
    cout<<endl;

    graph.reset();
    cout<<"递归深度优先遍历(DFS)序列为:"<<endl; 
    graph.DFS1(now);
    cout<<endl;

    graph.reset();
    cout<<"非递归深度优先遍历(DFS)序列为:"<<endl; 
    graph.DFS2(now);
    cout<<endl; 

    return 0;
}

这里写图片描述

1
0
查看评论

图深度优先遍历邻接矩阵表示

#include using namespace std; const int INF = 9999; int book[101],sum,n,e[101][101]; void dfs(int cur); int main() { int i,j,m,a,b; cin&g...
  • u012967763
  • u012967763
  • 2016-07-24 11:34
  • 1467

图的邻接矩阵表示方法以及遍历

下面的程序可以用来创建有向图,有向网,无向图,无向网。对于图来说如果来个顶点之间存在边,则在矩阵中用1表示,无边则用0表示。在网络中,边是对应权值的。 图的遍历可以分为深度优先遍历和广度优先遍历。 深度优先遍历的思想是,选择某个未被访问的顶点并访问,然后从该顶点出发,选择第一个和该顶点邻接的未被...
  • qq_20916555
  • qq_20916555
  • 2016-05-10 20:25
  • 783

采用邻接矩阵实现图的遍历

采用邻接矩阵实现图的遍历 (1)定义邻接矩阵的存储结构; (2)建立一个无向网G,如下图所示: (3)对G进行深度优先遍历,结出结果; (4)对G进行广度优先遍历,结出结果; #include #include #include #include using na...
  • migu77777
  • migu77777
  • 2016-11-23 09:24
  • 1430

图的遍历(DFS、BFS)使用邻接矩阵(数组)作为存储结构--C语言

#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <limits.h>#define MAX_VERTEX_NUM 20 //最大顶点个数 #define ...
  • haofight
  • haofight
  • 2017-01-17 17:34
  • 995

图的遍历与输出 (邻接矩阵和邻接表)

#include #include #include "graph.h" using namespace std; int main() { freopen("data.in" , "r" , stdin); // ...
  • S2637281620
  • S2637281620
  • 2016-12-05 18:15
  • 1618

图的邻接矩阵和DFS遍历

图的存储结构相对于线性表和树来说,是复杂了许多,而不是用一个线性表或者链表就能定义的。对于图来说,它的存储方式有邻接矩阵,邻接表,十字链表,邻接多重表和边集数组。在这里,要介绍的是如果使用邻接矩阵和邻接表来存储图结构。一、邻接矩阵图的邻接矩阵存储是用两个数组来完成的。一个一维数组存储定点信息(称为顶...
  • jeffleo
  • jeffleo
  • 2016-11-23 18:58
  • 1138

邻接矩阵的两种遍历算法

#include using namespace std;   const int maxsize=10; template class mgraph {     public:      ...
  • u013861473
  • u013861473
  • 2014-05-18 19:21
  • 640

图的邻接矩阵存储结构的实现及其遍历

图的邻接矩阵存储结构是一个很容易理解的存储结构,用一个矩阵记录两个顶点之间的关系,对于无向无权图,用0和1来表示两个顶点之间是否相邻即可,对于无向有权图,使用一个整型来表示两个顶点之间的弧的权值即可。 存储结构的定义: typedef char VertexType ; // 顶点类型 t...
  • bobopeng
  • bobopeng
  • 2013-10-25 16:23
  • 1333

图---邻接矩阵(建立,深度遍历,广度遍历)

    图的存储方式可以用邻接矩阵来表示,我们假定顶点序号从0开始,即图G的顶点集的一般形式是V(G)={v0,vi,…,Vn-1}。以下代码测试过,为图的邻接矩阵表示方式。/***********************************************...
  • akof1314
  • akof1314
  • 2009-07-28 20:01
  • 15228

初识图,图的存储(邻接矩阵,邻接链表)和深搜遍历

1.图的基本概念(1)图是由顶点集合与顶点间的关系集合组成的一种数据结构 Graph(V, E)其中V称为顶集(Vertices Set),E称为边集(Edges set) :V是顶点的非空有限集合,E是顶点之间关系的有限集合. (2)有序图:顶点对(v1, v2)是...
  • Dextrad_ihacker
  • Dextrad_ihacker
  • 2015-12-01 17:25
  • 1963
    个人资料
    • 访问:155550次
    • 积分:4927
    • 等级:
    • 排名:第6843名
    • 原创:329篇
    • 转载:0篇
    • 译文:0篇
    • 评论:80条
    博客专栏
    最新评论