论遍历的重要性
无论是什么数据结构,遍历就是其最重要最重要的操作。
因为查询操作是基于遍历的,无论是遍历索引还是遍历数据除了类哈希的方法。
而其他操作又是基于查询操作的。
图的遍历主要是两种形式DFS和BFS。
深度优先遍历(Depth_First_Search)
本来是想自己画一个图的,画到一半果断放弃,因为我没有画板emmm..吃不起饭了
我们注意上图,深度优先搜索顾名思义,就是一直往后面搜索的方法。
当我们访问了A结点,我们给A结点一个标记,于是我们知道我们已经遍历过A结点了。
当我们一直遍历到F结点的时候,下一个结点我们还要遍历A结点,但我们发现A结点已经被遍历过了于是我们就找它的第二条边访问G结点。
访问G结点的时候我们想遍历B和D结点,但是根据标记我们发现B和D结点已经被遍历过了,我们只能遍历H结点。
这时我们的I结点还是没有被访问到,这时我们需要一直回溯到结点D,我们发现D有一条相邻边I。这时我们遍历了整棵树。
说起来轻松,程序又不是我脑子控制到,我们注意到上面的叙述,如果你从没学过算法,编程语言也是一知半解,但你既然看图这一部分就证明你一定已经学过了线性表,这样的回溯操作一定是利用了栈这种数据结构。
这里我们用到的是递归,如果你对算法有一定的了解一定知道递归和栈的不解之缘。
如果图是全连通的,只需要一次DFS就可以了。
这里的图结结构参考我之前的图的存储结构:https://www.jianshu.com/p/4cd7930567d2
由于这个邻接矩阵和邻接表的实现方式基本上是一模一样所以这里只给了链表的。
广度优先遍历(Breadth_First_Search)
之前深度遍历是一条路走到黑,那么广度优先遍历自然是把一个结点的所有边看完,再看下一个结点我们还用刚才的图。
之前我们用的是递归(栈)的方式遍历了整个图,BFS标准算法是用到了普通队列
比如我们从A开始。
遍历A,A进队。
A出队,与A相邻(无向图)或A指向(有向图)的结点全部进队即B、F进队
B出队,与B相邻(无向图)或A指向(有向图)的结点全部进队即C、I、G进队
此时队列里有F、C、I、G,之后F出队重复上面的动作。
BFS不涉及递归相对好理解,这里我们还是只给出链表的表示方法
这个代码我还是模仿《大话数据结构》上的代码写的,我左思右想发现这个代码好像有问题。
这里我用了STL里的队列。
我们如果修改了for循环中i的值,如果这个图有多个连通分量,可能导致循环提前结束。这样就遍历不到全部结点,不过这个很好处理,我们只需要把循环控制变量和循环内用两个变量记录下标,就可以绕过这个问题,如果我理解错误欢迎简书私信我emmm...