图的遍历(上)——邻接矩阵表示

原创 2017年09月08日 18:46:36

概述

图作为数据结构书中较为复杂的数据结构,对于图的存储方式分邻接矩阵和邻接表两种方式。在这篇博客中,主要讲述邻接矩阵下的图的深度优先遍历(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;
}

这里写图片描述

版权声明:本文为博主原创文章,未经博主允许不得转载。若需转载,请注明http://blog.csdn.net/qq_30091945 举报

相关文章推荐

hihoCoder 1224 赛车 (dfs,邻接链表存边)

#1224 : 赛车 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 幻想乡有一个赛车场。赛车场里有N个地点。同时地点之间还有单向的道路存在。 这些道...

图论(一):DFS,BFS,邻接链表,并查集

本文总结了图的深度优先搜索,图的广度优先搜索,邻接链表和邻接矩阵的实现,并查集的实现。 0),预备知识         基础词汇:有向图,无向图,带权有向图,带权无向图,有向图中:即Vi--->Vj,...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

图的邻接矩阵和DFS遍历

图的存储结构相对于线性表和树来说,是复杂了许多,而不是用一个线性表或者链表就能定义的。对于图来说,它的存储方式有邻接矩阵,邻接表,十字链表,邻接多重表和边集数组。在这里,要介绍的是如果使用邻接矩阵和邻...

邻接矩阵遍历(无向图,邻接矩阵,DFS,BFS)

1、题目:  Problem Description 有多组数据,每组数据第一行有两个整数n、m,(0  Input 分别输出从标号为1点开始深度和广度优先搜索...

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

#include #include #include "graph.h" using namespace std; int main() { freopen("data.in" , "...

图的表示-邻接矩阵表示

描述图的邻接矩阵(Adjacency Matrix)表示是采用二维数组的方式。通过邻接矩阵可以立刻看出两顶点之间是否存在一条边,只需要检查邻接矩阵重行i和列j是否是非零值。对于无向图,邻接矩阵是对称的...
  • zwhlxl
  • zwhlxl
  • 2015-04-15 14:50
  • 1279

图的遍历(邻接矩阵)

package com.wzs; import java.util.LinkedList; import java.util.Queue; // 图的遍历 public class Graph {...

图的深度优先遍历DFS(邻接矩阵表示法)

1.前言期末复习算法,第三章讲到了图,所以想将课本中的算法实现。当写完代码的时候才发现这样的复习效率太低了,看书复习是复习,写代码是写代码。不过写完以后还是有点成就感的。2.参考文献http://bl...

图的广度优先遍历BFS(邻接矩阵表示法)

1.前言复习算法第四章——图中的路径,首先完成算法广度优先遍历,其中使用到了队列结构2.参考资料http://blog.csdn.net/lengyuhong/archive/2010/01/06/5...

图的广度优先遍历BFS(邻接矩阵表示法)

图的广度优先遍历BFS(邻接矩阵表示法) 1.前言 复习算法第四章——图中的路径,首先完成算法广度优先遍历,其中使用到了队列结构 2.参考资料 http://blo...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)