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

概述

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

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

daipuweiai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值