zoukankan      html  css  js  c++  java
  • 图——图的广度优先遍历

    1,前面两篇博文实现了邻接矩阵和邻接链表法实现图的数据结构,什么情况下选择合适的图的类型?从时间复杂度角度来对比下;

    2,时间复杂度的对比分析:

     

           1,邻接矩阵法操作性能更好、效率更高,更在意性能,则选择邻接矩阵法;

           2,链表矩阵法在空间使用率上更好,当环境资源紧张、内存比较小,选择邻接链表法;

          

    3,小结论:

           1,MatrixGraph 适用于内存资源富足的场合(性能较好);

           2,ListGraph 适用于内存资源受限的场合(节省空间);

          

    4,图的遍历:

           1,从图中的某一个顶点出发,沿着一些边访问图中的其它顶点,使得每个顶点最多被访问一次;

           2,注意:从某个顶点出发进行遍历,不一定能够访问到图中的所有顶点;

                  1,当始发顶点没有任何邻接顶点时;

                 

    5,图的遍历方式:

           1,广度优先(Breadth First Search):

                  1,以二叉树层次遍历的思想对图进行遍历;

           2,深度优先(Depth First Search):

                  1,以二叉树先序遍历的思想对图进行遍历;

                 

    6,广度优先(BFS):

     

           1,树的广度优先算法需要原材料:队列;

                 

    7,广度优先算法:

           1,原料:class LinkQueue<T>;

           2,步骤:

                  1,将起始顶点压入队列中;

                  2,队头顶点 V 弹出,判断是否已经标记(标记:转 2,未标记:转 3);

                         1,每个顶点只能访问一次,如果发现队头顶点已经打上标记,则已经访问过了,直接扔掉;

                  3,标记顶点,并将顶点 V 的邻接顶点压入队列中;

                         1,没有访问过的顶点的操作;

                  4,判断队列是否为空(非空:转 2,空:结束);

    8,广度优先算法示例:

          

    9,广度优先算法流程图:

     

           1,比树多了个标记数组,因为树结点的孩子不可能是此结点的父亲或祖先,但是图却可以是,所以要标记数组;

    10,广度优先算法实现:

     1    /* 广度优先算法,参数 i 为起始的顶点编号,图中的这个编号才具有唯一辨识性;以层次的方式对定点进行访问 ; 广度优先和深度优先唯一不同在于栈或队列的使用,使用队列存储邻接顶点则为广度优先,使用栈存储邻接顶点则为深度优先 ; 为了保持接口的一致性,仿照树里面层次遍历的操作设置函数接口 */
     2     SharedPointer< Array<int> > BFS(int i)
     3     {
     4         DynamicArray<int>* ret = NULL;  // 存储返回的顶点编号,要反应访问顶点编号的先后次序
     5 
     6         if( (0 <= i) && (i < vCount()) )
     7         {
     8             LinkQueue<int> q;  // 存放图的将要可能被遍历结点
     9             LinkQueue<int> r;  // 存放图的遍历后的结点
    10             DynamicArray<bool> visited(vCount()); //存储是否顶点是否被遍历的标记
    11 
    12             /* 初始的标记数组值设置 */
    13             for(int i=0; i<visited.length(); i++)
    14             {
    15                 visited[i] = false;
    16             }
    17 
    18             q.add(i);  // 向将要被可能访问结点的队列中加入元素
    19 
    20             /* 遍历循环开始 */
    21             while( q.length() > 0 )
    22             {
    23                 int v = q.front();  // 得到队列头部的顶点值
    24                 q.remove();  // 拿出这个顶点
    25 
    26                 if( !visited[v] )  // 判断是否被遍历过
    27                 {
    28                     SharedPointer< Array<int> > aj = getAdgacent(v);  // 拿到 v 顶点的邻接顶点并放到数组中
    29 
    30                     /* 将邻接顶点放到队列中 */
    31                     for(int j=0; j<aj->length(); j++)
    32                     {
    33                         q.add((*aj)[j]);  // 将邻接顶点放到队列中
    34                     }
    35 
    36                     r.add(v);  // 将顶点放到访问队列中去
    37 
    38                     visited[v] = true;  // 将访问标记设为访问
    39                 }
    40             }
    41 
    42             ret = toArray(r);  // 将队列转换为数组
    43         }
    44         else
    45         {
    46             THROW_EXCEPTION(InvalidParameterException, "Index i is invalid ...");
    47         }
    48 
    49         return ret;
    50     }

    11,广度优先算法实现的测试代码:

     1 #include <iostream>
     2 #include "MatrixGraph.h"
     3 
     4 using namespace std;
     5 using namespace DTLib;
     6 
     7 int main()
     8 {
     9     MatrixGraph<9, char, int> g;
    10     const char* VD = "ABEDCGFHI";
    11 
    12     for(int i=0; i<9; i++)
    13     {
    14         g.setVertex(i, VD[i]);  // 设置顶点相关的值为字符串 VD 中的内容
    15    }
    16 
    17     g.setEdge(0, 1, 0);  // 无向图、特殊的有向图,所以每个点之间的邻接矩阵对称, 这里权值为 0,只关心是否连接,不关心权值
    18     g.setEdge(1, 0, 0);
    19     g.setEdge(0, 3, 0);
    20     g.setEdge(3, 0, 0);
    21     g.setEdge(0, 4, 0);
    22     g.setEdge(4, 0, 0);
    23     g.setEdge(1, 2, 0);
    24     g.setEdge(2, 1, 0);
    25     g.setEdge(1, 4, 0);
    26     g.setEdge(4, 1, 0);
    27     g.setEdge(2, 5, 0);
    28     g.setEdge(5, 2, 0);
    29     g.setEdge(3, 6, 0);
    30     g.setEdge(6, 3, 0);
    31     g.setEdge(4, 6, 0);
    32     g.setEdge(6, 4, 0);
    33     g.setEdge(6, 7, 0);
    34     g.setEdge(7, 6, 0);
    35     g.setEdge(7, 8, 0);
    36    g.setEdge(8, 7, 0);
    37 
    38    SharedPointer< Array<int> > sa = g.BFS(0);
    39 
    40     for(int i=0; i<sa->length(); i++)
    41     {
    42         cout << (*sa)[i] << " ";
    43     }
    44     
    45     return 0;
    46 } 

    12,标号是图中唯一可以表示顶点的标志,要利用好;

    13,父类中实现其他时,可以调用子类中对纯虚函数的实现,因为当子类创建对象后,父类中的所有函数都被继承到了子类当中;

    14,小结:

           1,MatrixGraph 适用于资源富足的场合;

           2,ListGraph 适用于资源受限的场合;

                  1,时间复杂度高;

           3,广度优先按照“层次的方式”对定点进行访问;

                  1,同树的层次遍历;

           4,广度优先算法的核心是队列的使用;

                  1,邻接顶点的队列压入;

  • 相关阅读:
    android购物车的实现
    eclipse配置maven
    Android 高仿微信实时聊天 基于百度云推送
    如何使用Ubuntu online account API创建微博HTML5申请书
    C#创建和初始化类
    一个小的日常实践——距离阵列
    文本框中输入极限
    java阅读器hdfs单纯demo
    错误和问题解决的成本
    选择用户-保存选定的用户
  • 原文地址:https://www.cnblogs.com/dishengAndziyu/p/10926424.html
Copyright © 2011-2022 走看看