zoukankan      html  css  js  c++  java
  • 数据结构7——BFS

    一、重拾关键

    宽度优先搜索,也有称为广度优先搜索,简称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<<"请依次输入各顶点:
    ";
        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("每一行输入一条弧依附的顶点(空格分开):
    ");
        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	",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	",g.vex[j]);
                            q.push(j);                        //将顶点j入队列 
                        }
                    }
                    
                }
            }
        }
        
    } 
    
    int main()
    {
        Graph g;
        createGraph(g);
        BFSTraverse(g);
        return 0;
    }

    我的代码2:

     1 int n, m;
     2 int graph[105][105];
     3 bool vis[105];
     4 queue<int> q;
     5 
     6 void init()
     7 {
     8     memset(map,0,sizeof(map));
     9     memset(vis,0,sizeof(vis));
    10     while(!q.empty())   q.pop();
    11 }
    12 
    13 void BFS(int u)
    14 {
    15     vis[u] = 1;
    16     cout<<u<<"	";
    17     q.push(u);
    18     while(!q.empty()){
    19         int p = q.front();
    20         q.pop();
    21         for(int i=1;i<=n;i++){
    22             if(!vis[i] && graph[p][i]==1){
    23                 q.push(i);
    24                 cout<<i<<"	";
    25                 vis[i] = 1;
    26             }
    27         }
    28     }
    29 }
    30 
    31 void read()
    32 {
    33     init();
    34     cin>>n>>m;
    35     for(int i=1;i<=m;i++){
    36         int u, v;
    37         cin>>u>>v;
    38         graph[u][v] = graph[v][u] = 1;
    39     }
    40     for(int i=1;i<=n;i++){
    41         if(!vis[i])
    42             BFS(i);
    43     }
    44     cout<<endl;
    45 }
    46 
    47 int main()
    48 {
    49     read();
    50     return 0;
    51 }
    View Code

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

    //邻接表的广度遍历算法
    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;
                    }
                }
            }
        }
    }

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

    四、沙场练兵

    题目一、迷宫问题

  • 相关阅读:
    数据结构-链式结构-队列
    c数据结构-线性结构-队列
    栈的四则运算的运用
    C++/C—函数指针
    向显存写数据x8086
    结构体内存偏移量
    MFC-ComboBox控件的使用
    MFC的Edit text编辑框控件
    C/C++反汇编-各种表达式(加减乘)
    MFC- 学习控件-静态文本
  • 原文地址:https://www.cnblogs.com/xzxl/p/7230649.html
Copyright © 2011-2022 走看看