码迷,mamicode.com
首页 > 其他好文 > 详细

数据结构7——BFS

时间:2017-08-13 16:16:16      阅读:198      评论:0      收藏:0      [点我收藏+]

标签:ios   ons   ini   无向图   type   图的遍历   pre   lis   时间   

一、重拾关键

宽度优先搜索,也有称为广度优先搜索,简称BFS。类似于树的按层次遍历的过程。

初始状态:图G所有顶点均未被访问过,任选一点v。

遍历过程:假设从图中某顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直至图中所有已被访问的顶点的邻接点都被访问到。若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。换句话说,广度优先搜索遍历图的过程中以v为起始点,由近至远,依次访问和v有路径相通且路径长度为1,2,…的顶点。

 

二、算法过程

以如下图的无向图G4为例,进行图的宽度优先搜索:

技术分享

假设从顶点v1出发进行搜索,首先访问v1和v1的邻接点v2和v3,然后依次访问v2的邻接点v4和v5及v3的邻接点v6和v7,最后访问v4的邻接点v8。由于这些顶点的邻接点均已被访问,并且图中所有顶点都被访问,由些完成了图的遍历。得到的顶点访问序列为:技术分享

和深度优先搜索类似,在遍历的过程中也需要一个访问标志数组。并且,为了顺次访问路径长度为2、3、…的顶点,需附设队列以存储已被访问的路径长度为1、2、… 的顶点。

 

三、代码实现

邻接矩阵做存储结构时,广度优先搜索的代码如下。

/*    图的BFS遍历    */
//邻接矩阵形式实现 
//顶点从1开始 
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn = 105;        //最大顶点数 
typedef int VertexType;     //顶点类型
bool vis[maxn];  

struct Graph{               //邻接矩阵表示的图结构
    VertexType vex[maxn];   //存储顶点
    int arc[maxn][maxn];    //邻接矩阵
    int vexnum,arcnum;      //图的当前顶点数和弧数
};

void createGraph(Graph &g)  //构建有向网g
{
    cout<<"请输入顶点数和边数:";
    cin>>g.vexnum>>g.arcnum;
     
    //构造顶点向量
    cout<<"请依次输入各顶点:\n";
    for(int i=1;i<=g.vexnum;i++){
        scanf("%d",&g.vex[i]);
    }
     
    //初始化邻接矩阵
    for(int i=1;i<=g.vexnum;i++){
        for(int j=1;j<=g.vexnum;j++){
            g.arc[i][j] = 0;
        }
    }
     
    //构造邻接矩阵
    VertexType u,v;     //分别是一条弧的弧尾(起点)和弧头(终点)
    printf("每一行输入一条弧依附的顶点(空格分开):\n");
    for(int i=1;i<=g.arcnum;i++){
        cin>>u>>v;
        g.arc[u][v] = g.arc[v][u] = 1; 
    }  
}

//邻接矩阵的宽度遍历操作
void BFSTraverse(Graph g)
{
    queue<int> q;                        //声明队列q 
    for(int i=1;i<=g.vexnum;i++){
        vis[i] = false;
    }
    for(int i=1;i<=g.vexnum;i++){        //对每个顶点做循环 
        if(!vis[i]){
            vis[i] = true;
            printf("%d\t",g.vex[i]);
            q.push(i);                    //将此节点入队列 
            while(!q.empty()){
                int m = q.front();
                q.pop();                //出队列,值已赋给m 
                for(int j=1;j<=g.vexnum;j++){
                    if(g.arc[m][j]==1 && !vis[j]){        //如果顶点j是顶点i的未访问的邻接点
                        vis[j] = true;
                        printf("%d\t",g.vex[j]);
                        q.push(j);                        //将顶点j入队列 
                    }
                }
                
            }
        }
    }
    
} 

int main()
{
    Graph g;
    createGraph(g);
    BFSTraverse(g);
    return 0;
}

技术分享

 

对于邻接表的广度优先遍历,代码与邻接矩阵差异不大, 代码如下。

//邻接表的广度遍历算法
void BFSTraverse(GraphList g)
{
    int i;
    EdgeNode *p;
    Queue q;
    for(i = 0; i < g.numVertexes; i++)
    {
        visited[i] = FALSE;
    }
    InitQueue(&q);
    for(i = 0; i < g.numVertexes; i++)
    {
        if(!visited[i])
        {
            visited[i] = TRUE;
            printf("%c ", g.adjList[i].data);   //打印顶点,也可以其他操作
            EnQueue(&q, i);
            while(!QueueEmpty(q))
            {
                int m;
                DeQueue(&q, &m);
                p = g.adjList[m].firstedge;     找到当前顶点边表链表头指针
                while(p)
                {
                    if(!visited[p->adjvex])
                    {
                        visited[p->adjvex] = TRUE;
                        printf("%c ", g.adjList[p->adjvex].data);
                        EnQueue(&q, p->adjvex);
                    }
                    p = p->next;
                }
            }
        }
    }
}

分析上述算法,每个顶点至多进一次队列。遍历图的过程实质是通过边或弧找邻接点的过程,因此广度优先搜索遍历图的时间复杂度和深度优先搜索遍历相同,两者不同之处仅仅在于对顶点访问的顺序不同。

 

四、沙场练兵

题目一、迷宫问题

 

数据结构7——BFS

标签:ios   ons   ini   无向图   type   图的遍历   pre   lis   时间   

原文地址:http://www.cnblogs.com/xzxl/p/7230649.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!