图表算法—无向图

1. 图表算法

  本篇随笔写的是图表算法。图表可以大致分为两种:无向图和有向图。

  无向图例子:

  

  有向图例子:

  

  从上述例子中可以看出,一个图表是由数个顶点和边组成的。

  其中,无向图的边是没方向的,即两个相连的顶点可以互相抵达。

  而有向图的边是有方向的,即两个相连的顶点,根据边的方向,只能由一个顶点通向另一个顶点。(当然,如有向图例子中的2和3,由于有两个指向对方的方向,所以2和3是互通的。)

   本文写的是无向图的算法,有向图的算法将写在下篇随笔中。

2. 无向图(UndirectedGraph)

  要讨论无向图的算法前,首先要讨论如何创建一个无向图。

  创建无向图有两个关键点:

  a. 这个无向图有哪些点

  b. 哪些点可以通往哪些点

  举个例子:

  

  显然,这个无向图有13个点。0可以通往1,2,5,6;6可以通往0,4;5可以通往0,3,4。

  即0的邻居点有1,2,5,6;6的邻居点有0,4。

  那么,我们怎么告诉程序这个无向图呢?

  目前有两种主流的方法:邻接矩阵(Adjacency-matrix)和邻接列表(Adjacency-list)。

  邻接矩阵:

  

  如果两个点相邻,则用1表示,否则用0。例如1是0的邻居点,所以0和1相交对应的格子为1。

  从这个图可以看出,如果每个点不是与大量的其它点互为邻居,则会有很多0出现。如果点的数量庞大,矩阵将十分巨大,且有很多空间浪费(0占据的格子)。

  邻接列表:

  

  就是用一个数组把所有点装起来,每个位置是由对应点的所有邻居点形成的数组。

  即adj[0]=6,2,1,5(0可以通往1,2,5,6);adj[6]=0,4(6可以通往0,4)。

  这个列表比较适合每个点只与少量其它点相邻的情况。

  我们可以根据实际情况进行选择用列表还是矩阵。

  通过创建一个矩阵或者列表,程序可以知道这个无向图有哪些点和点与点之间的联系。如果要加点或者删点,应该不难实现,这里不做详述。

  接下来,我们讨论算法:深度优先搜索(depth-first search)和广度优先搜索(breadth-first search)。

 

3.深度优先搜索(depth-first search)

  深度优先搜索可以解决的问题有:

  a. 给定一个点,求所有它能抵达的所有点。

  b. 给定两个点,它们是否能抵达彼此,如果能,求路线。

  等等。

  这个算法简单地用一句话概括就是:一路走到尽头,然后返回上一个分支,走另一条路到尽头,再返回,再走其他路,直到全部走完为止。

  从例子入手:

  

  为了方便讲解,作下图:

  

  0~12代表着图中的所有点。

  一开始所有点标记为False(F),当我们走到某个点后,此点标记为True(T)。标记过的点不需要再走一次。

  EdgeTo记录了部分路线,所有部分路线可以整合成一个完整的路线。例如从E点抵达A点,则记为EdgeTo[A]=E;

  Group记录了这些点形成了多少个组,且哪些点分别属于哪些组。这样可以瞬间查到两个点是否相连。例如本例中分为3组,其中7,8属于一组;9,10,11,12属于第二组;剩下的属于第三组。

  先看最大的这组:

  

  从0开始,先把0标记了(变红)。记0为第0组。

  

  0的邻居点有4个,随便选一条路来走。例如去2:2标记为True;2从0来,故EdgeTo[2]=0; 2与0属于同一组:0组。

  

  然后2只有一个邻居点0,但0已标记为T,故不用走。2已经无路可走了,返回上一个分支点0。

  0再选择走其它路:6。6标记为True;6从0来,故EdgeTo[6]=0; 6与0属于同一组:0组。

  

  然后6有两个邻居点:0和4。由于0已标记为T,不走。

  去4:4标记为True;4从6来,故EdgeTo[4]=6; 4与6属于同一组:0组。

 

  然后4有三个邻居点:6,3,5。由于6已标记为T,不走。

  随便选一个路走:5。5标记为True;5从4来,故EdgeTo[5]=4; 5与4属于同一组:0组。

  然后5有三个邻居点:0,3,4。由于0,4已标记为T,不走。

  只能走3:3标记为True;3从5来,故EdgeTo[3]=5; 3与5属于同一组:0组。

 

  然后3有两个邻居点:5和4。由于4,5已标记为T,不走。

  3无路可走,返回上一个分支5。5有三个邻居点:0,3,4。由于0,3,4已标记为T,不走。

  5无路可走,返回上一个分支4。4有三个邻居点:5,3,6。由于3,5,6已标记为T,不走。

  4无路可走,返回上一个分支6。6有两个邻居点:0,4。由于0,4已标记为T,不走。

  6无路可走,返回上一个分支0。0有四个邻居点:5,1,2,6。由于5,2,6已标记为T,不走。

  0走向1:1标记为True;1从0来,故EdgeTo[1]=0; 1与0属于同一组:0组。

  1有一个邻居点:0。由于0已标记为T,不走。返回上一个分支0。

  0有四个邻居点:5,1,2,6。由于5,2,6,1已标记为T,不走。

  0无路可走,且无上一个分支点。查找标记为F的其它点,随便选一个来走,如7。

  7标记为True;7属于组1。

  

  然后重复上述过程,直到所有点标记为T为止。

  看懂上述例子的思路,那么通用思路也是一样的。如果想查1和6是否相连,只需看它们所属组别是否相同即可。

  如查1到6的路径,从1和6分别查EdgeTo,查到重复点,则把路线结合即可。

代码大概是这样的:

  

 

4. 广度优先搜索(breadth-first search)

  从深度优先搜索的思路上看,显然不适合用于寻找最短路径。

  这里介绍另一种思路:广度优先搜索。此算法需要用到队列(queue),对队列不熟悉的,可以先看下队列

  从例子入手:

  

  为了方便讲解,作下图:

  

  Marked和EdgeTo与深度优先搜索的一样,DistTo表示起始点与目标点的距离。如:0与3的距离为2,即DistTo[3]=2。

  先看最大的这组:

  

  从0开始,先把0标记了(变红)。记0到0的距离为0。(从哪个点开始可以根据需求来决定。)把0加入到队列A中。

  

  0的邻居点有4个:5,1,2,6。队列A输出一个值:0,队列A按顺序输入值5,1,2,6。(这个顺序没所谓,1,6,5,2也行。)

  5,1,2,6全部标记为True,从0点来,距离0点为1:

  

  队列A输出一个值,如果上一步是按5,1,2,6顺序输入的,则这里输出的是5.

  5的邻居点有3个:0,3,4。由于0已经标记为True,所以不管。将3,4按顺序输入到队列A中(当然,顺序无所谓)。 

   3,4全部标记为True,从5点来,距离0点为2:

  

  队列A输出一个值,如果之前那步是按5,1,2,6顺序输入的,则这里输出的是1.

  1的邻居点有1个:0。由于0已经标记为True,所以不管。

  队列A输出一个值,如果之前那步是按5,1,2,6顺序输入的,则这里输出的是2.

  2的邻居点有1个:0。由于0已经标记为True,所以不管。

  队列A输出一个值,如果之前那步是按5,1,2,6顺序输入的,则这里输出的是6.

  6的邻居点有2个:0,4。由于0,4已经标记为True,所以不管。

  队列A输出一个值,如果上一步是按3,4顺序输入的,则这里输出的是3.

  3的邻居点有2个:5,4。由于5,4已经标记为True,所以不管。

  队列A输出一个值,如果上一步是按3,4顺序输入的,则这里输出的是4.

  4的邻居点有3个:5,3,6。由于3,5,6已经标记为True,所以不管。

  队列A为空,这部分处理完毕。

  其它部分也是相同处理方法,DistTo要小心处理,一般要遍历全部的时候,DistTo是不需要的。DistTo一般用于寻找两个点之间的最短距离与路线。

  当然也可以像深度优先处理那样加入Group来记录哪些点在哪个团体中。

  通用思路可以从例子中看出来,实在看不出的,可以看下面的代码。

代码大概是这样的:

  

 

转载于:https://www.cnblogs.com/mcomco/p/10298021.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这道题要设计并验证以下算法:带权图表表示,实现有向图的广度优先搜索和无向图的深度优先搜索,以实现有向图的宽度优先搜索和无向图的深度优先搜索,并且要考虑有向图和无向图的广度优先搜索和深度优先搜索的优先级问题。 ### 回答2: 在图的搜索算法中,广度优先搜索(BFS)和深度优先搜索(DFS)是两种常用的算法。本题要求设计并验证一个能够实现有向图的BFS和无向图的DFS的算法。为了达成这个目的,我们需要分别说明有向图和无向图的BFS和DFS的实现方法。 首先来看BFS。对于一个有向图,我们可以使用邻接表来表示。实现BFS需要使用一个队列来保存待访问的顶点。我们先将起始点入队,并标记它为已访问。然后依次取出队首点的所有邻接点,并将未访问的邻接点入队。重复这个过程,直到队列为空。这样可以保证我们逐层遍历整个图,找到所有与起始点连通的点。需要注意的是,当我们进行BFS时,需要记录每个顶点到起始点的距离,同时可能需要记录一些其他信息,如前驱节点等。 接下来看DFS的实现。对于无向图,我们依然使用邻接表来表示。DFS的实现可以使用递归或栈来实现。我们先选择一个起始点,将其标记为已访问,并访问它的邻接点。然后对于每个未访问的邻接点,进行递归访问。这个过程会不断递归,直到当前终止节点的所有邻接点均被访问过。需要注意的是,递归过程中需要记录每个顶点的访问顺序、状态等信息。 为了验证这个算法,我们需要编写程序,并且进行测试。我们可以使用一些经典的图例进行测试,如克鲁斯卡尔算法中使用的7个点的有向图等。对于测试用例,我们需要确定起始点,并在进行搜索前输出图的邻接表信息和搜索算法要求的其他信息。然后进行搜索,根据搜索的结果来判断算法的正确性。我们需要验证广度优先搜索能够找到所有与起始点连通的点,而深度优先搜索能够遍历整个图。同时,我们还需要对于一些特殊情况进行测试,如图为空、只有一个顶点、有向图中存在环、无向图中存在重边等。 综上,本题要求我们设计并验证一个能够实现有向图的BFS和无向图的DFS的算法。我们可以使用邻接表来表示图,使用队列和递归/栈来实现BFS和DFS。测试时需要选择好测试用例,并对于特殊情况进行特别关注。通过这个过程,我们可以更好地掌握图的搜索算法,并深入理解基础算法的设计和实现过程。 ### 回答3: 一、算法设计思路: 对于带权图,我们可以在邻接表中记录边的权值信息。在广度优先搜索时,需要使用队列来进行遍历。在遍历过程中,访问顶点时需要将其标记为已访问,并将其相邻的未访问的顶点加入队列中。在每次从队列中取出一个顶点时,需要输出该顶点的信息。 在深度优先搜索时,可以使用递归来遍历无向图。每次访问时,需要将当前顶点标记为已访问,并遍历与其相邻的未访问的顶点,直到遍历完整个图为止。 二、算法验证: 我们可以通过编写代码并对实际图进行遍历来验证算法的正确性。在这里,我们以以下有向图和无向图为例进行验证。 (1)有向图: 该图的邻接表表示为: 0:1(2) 2(3) 1:3(4) 2:3(1) 4(5) 3:4(2) 4:5(6) 5: 使用广度优先搜索的结果为:0 1 2 3 4 5 使用深度优先搜索的结果为:0 1 3 4 5 2 (2)无向图: 该图的邻接表表示为: 0:1 2 1:0 3 4 2:0 4 3:1 4:1 2 使用广度优先搜索的结果为:0 1 2 3 4 使用深度优先搜索的结果为:0 1 3 4 2 通过对以上图的遍历结果可以验证广度优先搜索与深度优先搜索算法的正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值