图(深度优先搜索&&广度优先搜索)

来源:互联网 发布:好的网络推手公司 编辑:程序博客网 时间:2024/06/05 21:52
  
    图是一种非线性结构,由顶点集合(vertex)及顶点间的关系集合组成的一种数据结构
    Graph=(V,E);V={x|x是顶点的集合};E={<x,y>|x,y属于V}
    如下图
            

    图可以分为有向图和无向图两种。  
    
    完全图:在由n个顶点组成的无向图中,若有N(N-1)/2条边,则称为无向完全图(也就是说任意两个顶点间都有边相连)
    
    权重:在一些图中,边具有与之相关的数值,称为权重。(权重可以表示从一个顶点到另一个顶点的距离/花费的代价/所需的时间/次数等)

    邻接顶点:如果(u,v)是图中的一条边,则u和v互为邻接顶点
 
    度:与顶点v关联的边的数目称为顶点v的度

    连通图:在无向图中V1到V2有路径,则称V1和V2是连通的,如图中任意两个顶点都是连通的,则称此图是连通图

    强连通图:在有向图中,若每一对顶点之间都存在路径,则称此图为强连通图

    生成树:一个无向连通图的生成树是它的极小连通子图,若图中有N个节点,则其生成树有N-1条边构成

    邻接矩阵:将所有的顶点信息组织成一个顶点表,然后利用矩阵来表示各顶点之间的邻接关系,称为邻接矩阵

    最小生成树(无向图)
    连通图由N个顶点组成,生成树必须含有N个顶点、N-1条边
(1)只能用连通图的边来构造最小生成树
(2)只能恰好用N-1条边来连接图中的顶点
(3)选用的这N-1条边不能构成回路
(具体实现方法后面再讲)

    深度优先遍历(DFS)
(1)访问指定的起始顶点
(2)若当前访问的顶点的邻接顶点有未被访问,则任选一个访问;反之,退回到最近访问过得顶点;直到与起始顶点相通的全部顶点都访问完毕
(3)若此时图中尚有顶点未被访问,则再选其中一个顶点作为起始顶点访问,转(2);反之,遍历结束
连通图的深度优先遍历类似于树的先根遍历
    如何判别V的邻接顶点是否被访问?
    解决办法:为每个顶点设置一个访问标志位。首先将图中每个顶点的访问标志设为FALSE,之后搜索图中每个顶点,如果未被访问,则以该顶点为起始点,进行深度优先遍历,否则检查下以顶点(具体实现方法为递归方式)

访问指定的起始顶点,若当前访问的顶点的邻接顶点有未被访问的,则任选一个访问

反之,退回到最近访问过的顶点,直到与起始顶点相通的全部顶点都访问完毕
此时与起始顶点1相通的全部顶点都访问完毕


再也没有未被访问的节点,回退到起始顶点,结束搜索

顶点访问序列:V1、V2、V4、V3、V5(序列不唯一)

    采用递归方式实现



具体实现过程中需要借助一个标志数组来记录该顶点是否被访问,标志数组的初始状态如下图

邻接表如下


(1)(顶点访问顺序,按权重从大到小)起始顶点为西安,下标为0


 按邻接表顺序访问,实现访问顶点“西安”,当访问到顶点“杭州”时,访问标志位为false,递归子问题
(2)起始顶点为“杭州”,下标4

访问顶点“杭州”,并将访问标志位置为true,按顶点“杭州”的邻接表顺序访问,第一顶点为“西安”,但访问标志位为true,跳过该顶点,访问顶点“苏州”,此时访问标志位为false,递归子问题
(3)起始顶点为“苏州”,下标为“5”

访问顶点“苏州”,并将访问标志位置为true,按顶点“苏州”的邻接表顺序访问,第一顶点为“拉萨”,访问标志位为false,递归子问题
(4)起始顶点为“拉萨”,下标为“3”

访问顶点“拉萨”,并将访问标志位置为true,按顶点“拉萨”的邻接表顺序访问,第一顶点为“苏州”,但访问标志位为true,跳过该顶点,访问顶点“成都”,此时访问标志位为false,递归子问题
(5)起始顶点为“成都”,下标为“2”

访问顶点“成都”,并将访问标志位置为true,按顶点“成都”的邻接表顺序访问,第一顶点为“拉萨”,但访问标志位为true,跳过该顶点,访问顶点“西安”,访问标志位为true,此时递归返回
递归返回到上层顶点“拉萨”的邻接表,顶点“苏州”,“成都”的访问标志位为true,继续向下,访问到顶点“上海”时,访问标志位为false,递归子问题
(6)起始顶点为“上海”,下标为“1”

访问顶点顶点“上海”,将其访问标志位置为true,其邻接表的其他顶点的访问标志文均为true,递归返回
上层邻接表的顶点访问标志位也均为true,继续返回,直至返回到起始顶点“西安”,发现所有顶点均已被访问,递归退出。
访问顺序为:西安、杭州、苏州、拉萨、成都、上海

具体代码实现过程


程序运行结果为


    广度优先搜索
    方法:从图的某一节点出发,首先依次访问该节点的所有邻接顶点,再按这些顶点被访问的先后次序依次与它们想邻接的所有未被访问的顶点,重复此过程,直至所有顶点均被访问为止
  


    依靠队列和顺序表来实现
    队列的特点是先进先出
初始时设置访问标志数组均为false
(1)下标0入队,队列特点是先进先出,将下标0出队,此时顶点“西安”(下标为0)的访问标志位false,访问该顶点,将其标志置为true,以顶点“西安”的邻接表开始访问,此时顶点“杭州”,“上海”,“成都”的访问标志均为false,将它们依次入队
此时队列情况为

(2)将顶点“杭州”(下标为4)出队,访问该顶点,并将其访问标志置为true,将顶点“杭州”的邻接表中的顶点访问标志为false的入队


(3)将顶点“上海”(下标为1)出队,访问该顶点,并将其访问标志设置为true,将顶点“上海”的邻接表中的邻接顶点全部依次入队

(4)将顶点“成都”(下标为2)出队,访问该顶点,并将其访问标志设置为true,将顶点“成都”的邻接表中访问标志为false的邻接顶点全部依次入队

(5)将顶点“苏州”(下标为5)出队,访问该节点,并将其访问标志设置为true,将其邻接表中访问标志为false的邻接顶点入队

(6)将顶点“拉萨”(下标为3)出队,访问该节点,并将其标志设置为true,将其邻接表中访问标志位false的邻接顶点入队

此时顶点“拉萨”邻接表里的顶点访问标志都为true,所以没有新的节点入队
(7)将顶点“拉萨”出队,其访问标志为true,此时队列为空,所有节点都遍历结束
访问顺序为:西安[0]、杭州[4]、上海[1]、成都[2]、苏州[5]、拉萨[3]
具体实现如下

程序运行结果为





    这篇博客我主要写了图的深度优先搜索和广度优先搜索的实现方法,图里还有一个很重要的点是最小生成树,不想把一篇博客写的太长了,所以将最小生成树另起一篇。关于图的所有代码都在下篇最小生成树的博客里贴出来。