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

原创 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

相关文章推荐

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

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

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

图的深度遍历 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 请定一个无向图,顶点编号从0到n-1,用深度优先搜...

图的递归深度遍历(邻接矩阵表示)

#include "stdafx.h" #include using namespace std; const int MAX_VERTEX_NUM=5; //邻接矩阵最大的维数 ...
  • gningh
  • gningh
  • 2012年11月16日 16:10
  • 807

【c/c++ 算法/数据结构】 邻接矩阵表示图,深度,广度优先遍历 算法设计+代码+图片

*问题描述: 建立图的存储结构(图的类型可以是有向图、无向图、有向网、无向网,学生可以任选两种类型),能够输入图的顶点和边的信息,并存储到相应存储结构中,而后输出图的邻接矩阵。   1、邻接矩阵...
  • wzwdcld
  • wzwdcld
  • 2014年05月24日 15:15
  • 3045

【数据结构】邻接矩阵表示法的图的深度广度优先遍历递归和非递归遍历

假设有以下结构的图: 用邻接矩阵表示如下: 因为他是无向图,我们可以发现他的矩阵是对角对称的。矩阵中每一行每一列都可以看成是一个顶点,矩阵中的元素表示着该顶点与其他顶点的关系,当元素的值为1说明...
  • e_one
  • e_one
  • 2016年02月02日 16:26
  • 7094

无向图的邻接矩阵表示和遍历

#include #include #include using namespace std; typedef char vertexType; //顶点的数据类型...
  • wwj_ff
  • wwj_ff
  • 2015年06月12日 15:08
  • 1399

图的邻接矩阵表示、广度优先遍历和深度优先遍历

如上如的所示,对图节点进行编号,每个节点又有相应的编号和值。因此图可以有一个二阶矩阵来记录各个节点的联通关系,由一个数组来记录各个节点的内容。图的广度优先遍历和深度优先遍历。 输出如下: ...

java 图的邻接矩阵表示,深度优先遍历,广度优先遍历

转载:http://blog.csdn.net/yxmmao/article/details/51586540 1 . 创建图的邻接矩阵数据结构 public class MGraph {...

图(2)—— 邻接矩阵表示法

图的存储结构 图的存储结构比较复杂,其复杂性主要表现在:  ◆ 任意顶点之间可能存在联系,无法以数据元素在存储区中的物理位置来表示元素之间的关系。  ◆ 图中顶点的度不一样,有的可能相差很大,若...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:图的遍历(上)——邻接矩阵表示
举报原因:
原因补充:

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