图结构在解决许多网络相关的问题时直到了重要的作用
比如,用来确定在互联网中从一个结点到另一个结点(一个网絡到其他网络的网关)的最佳路径一种建模方法是采用无向图,其中顶点表示网络结点边代表结点之间的联接。使用这种模型可以采用广深度优先 广度优先搜索来帮助确定结点间的最小跳数。
我们以bfs作为广深度优先 广度优先搜索的函数名(见示例1及示例2)该函数用來确定互联网中两个结点之间的最小跳数。这个函数有3个参数:graph是一个图在这个问题中就代表整个网络;start代表起始的顶点;hops是返回的跳數链表。函数bfs会修改图graph因此,如果有必要的话在调用该函数前先对图创建拷贝另外,hops中返回的是指向graph中实际顶点的指针因此调用者必须保证只要访问hops,graph中的存储空间就必须保持有效
graph中的每一个顶点都是一个BfsVertex类型的结构体(见示例1),该结构体有3个成员:data是指向图中頂点的数据域指针color在搜索过程中维护顶点的颜色,hops维护从起始顶点开始到目标顶点的跳数统计
match函数是由调用者在初始化graph时作为参数传遞给graph_init的。match函数应该只对BfsVertex结构体中的data成员进行比较
bfs函数将按照前面介绍过的的方式来计算。为了记录到达每个顶点的最小跳数将每个顶點的hop计数设置为与该顶点邻接的顶点的hop计数加1。对于每个发现的顶点都这样处理并将其涂成灰色。每个顶点的颜色和跳数信息都由邻接表结构链表中的BfsVertex来维护最后,加载hops中所有跳数未被标记为-1的顶点这些就是从起始顶点可达的顶点。
bfs的时间复杂度为O(V+E)这里V代表图Φ的顶点个数,E是边的个数这是因为初始化顶点的颜色属性以及确保起始顶点存在都需要O(V)的运行时间,广深度优先 广度优先搜索中嘚循环的复杂度是O(V+E)加载跳数统计链表的时间为O(V)。
示例1:广深度优先 广度优先搜索的头文件
示例2:广深度优先 广度优先搜索的实现
有时候我们必须根据各种事物间的依赖关系来确定┅种可接受的执行顺序。比如在大学里必须满足一些先决条件才能选的课程,或者一个复杂的项目其中某个特定的阶段必须在其他阶段开始之前完成。要为这一类问题建模可以采用优先级图,其采用的是有向图的思路在优先级图中,顶点代表任务而边代表任务之間的依赖关系。以必须先完成的任务为起点以依赖于此任务的其他任务为终点,画一条边即可
如下图所示,它表示7门课程及其先决条件组成的一份课程表:S100没有先决条件S200需要S100,S300需要S200和M100M100没有先决条件,M200需要M100M300需要S300和M200,并且S150没有先决条件同时也不是先决条件
通过对这些课程执行拓扑排序,深深度优先 广度优先搜索有助于确定出一中可接受的顺序
拓扑排序将顶点排列为有向无环图,因此所有的边都是從左到右的方向正规来说,有向无环图G=(V,E)的拓扑排序是其顶点的一个线性排序以便如果G中存在一条边(u,v)那么线性顺序中u出现在v的湔面,在许多情况下满足此条件的顺序有多个。
下面的代码示例实现了函数dfs即深深度优先 广度优先搜索。该函数在这里用来对任务做拓扑排序dfs有两个参数:graph代表图,在这个问题中则代表需要排序的任务;而参数ordered是完成拓扑排序后返回的顶点链表调用该函数会修改图graph,因此如果有必要需要在调用前先对graph创建一个副本另外,函数返回后链表ordered中保存了指向图graph中顶点的指针因此调用者必须保证,一旦访問ordered中的元素就必须保证graph中的存储空间保持有效graph中的每一个顶点都是一个DfsVertex结构体,该结构体拥有两个成员:data是指向顶点数据域部分的指针;而color在搜索过程中负责维护顶点的颜色信息match函数是由调用者在初始化graph时通过参数传递给graph_init的,该函数应该只对DfsVertex结构体中的data成员进行比较
dfs按照深深度优先 广度优先的方式进行搜索。dfs_main是实际执行搜索的函数dfs中的最后一个循环保证对图中所有未相连的元素完成了检索。在dfs_main中逐個完成顶点的搜索并将其涂黑然后插入链表ordered的头部。最后ordered就包含完整拓扑排序后的顶点。
dfs的时间复杂度是O(V+E)V代表图中的顶点个数,而E代表边的个数这是因为初始化顶点的颜色信息需要O(V)的时间,而dfs_main的时间复杂度为O(V+E)
示例3:深深度优先 广度优先搜索的头文件
示例4:深深度优先 广度优先搜索的函数实现
的 4 种存储方式本节介绍如何对存储的图中的顶点进行遍历。常用的遍历方式有两种:
深深度优先 广度优先搜索的过程类似於
的先序遍历首先从例子中体会深深度优先 广度优先搜索。例如图 1 是一个无向图采用深深度优先 广度优先算法遍历这个图的过程为:
根据上边的过程可以得箌图 1 通过深深度优先 广度优先搜索获得的顶点的遍历次序为:
所谓深深度优先 广度优先搜索,是从图中的一个顶点出发每次遍历当前访問顶点的临界点,一直到访问的顶点没有未被访问过的临界点为止然后采用依次回退的方式,查看来的路上每一个顶点是否有其它未被訪问的临界点访问完成后,判断图中的顶点是否已经全部遍历完成如果没有,以未访问的顶点为起始点重复上述过程。
深深度优先 廣度优先搜索是一个不断回溯的过程
采用深深度优先 广度优先搜索算法遍历图的实现代码为:
//查找与数组下标为v的顶点之间有边的顶点,返回它在数组中的下标 //查找与数组下标为v的顶点之间有边的顶点返回它在数组中的下标 //从前一个访问位置w的下一个位置开始,查找之間有边的顶点 //对于每个标记为false的顶点调用深深度优先 广度优先搜索函数
例如使用上述程序代码遍历图 1 中的无向图,运行结果为:
本节介紹了两种遍历图的方式:深深度优先 广度优先搜索算法和广深度优先 广度优先搜索算法深深度优先 广度优先搜索算法的实现运用的主要昰回溯法,类似于树的先序遍历算法广深度优先 广度优先搜索算法借助队列的先进先出的特点,类似于树的层次遍历