【数据结构】【二叉树】五、图的深度优先遍历(DFS) && 广度优先遍历(BFS)

一、深度优先遍历(DFS)

1. 理解

1.1 回顾二叉树的前序遍历

深度优先遍历就像二叉树中的前序遍历,一竿子插到底,发现没法前进了,再退回到上一个节点,看有没有另一条岔路可走,如果有,就再一竿子插到底;如果没有,就再退回到上上个节点……这样不断递归,直到左右节点都被遍历过。

不妨先来看看二叉树前序遍历
在这里插入图片描述
前序遍历步骤

:从根节点A开始,无脑走左子树、左子树、左子树……直到行进到G,他没有左子节点,也就是没有左子树可走了,再去找右子树,由于本图中的二叉树比较简单,G也没有右子树可走了,那么就退回到G的上一个节点D

:D的左子树已经走过了,现在就走D的右子树;

:把D的右子树当作一棵全新的树来走,也就是说进入D的右子树的根节点H后,也无脑走左子树,由于本图中的二叉树比较简单,H没有左子树,因此再看H的右子树,也没有,那么就退回到D

:现在D的左右子树都走过了,D下已经没有未遍历的子节点了,因此再退回到D的上一个节点B,去找B的右子树,发现也没有,就再退回到A

A的左子树已经走过了,就走A的右子树,把A的右子树当作一棵全新的树来走,先无脑走左子树,再退回来……

1.2 图的深度优先遍历(DFS)

图也一样,拿到根节点,先一竿子插到底,直到前面没有节点了,就退回到上一个节点,查看有没有另一条岔路,如果,就把这另一条岔路当作全新的一个图来走;如果没有,就退回到上上个节点,看有没有另一条岔路……。

不同的是:

:图可能会是一个环,即没有头也没有尾,因此在一竿子插到底的过程中,如果遇到了已经遍历过的节点,说明已经到了环的头和尾的连接处,再往前就全都是走过的节点,就不要再往前走了,要开始往回退;

:对二叉树中的一个节点,往它的下一步走时,只有子树和子树两个选择,而可能往下有三条、四条、五条甚至更多条岔路可以走,因此,需用while或for循环来确保经过每条岔路。

一个图的深度优先遍历(DFS),如下图所示:
在这里插入图片描述
先按照 0 -> 1 -> 2 -> 3 -> 4 -> 5的顺序无脑插入,直到5的下一个是0,走过了,所以退回到5,看5还有没有未走过下一个节点,发现了G所以G无脑往下走;

经过 G -> H,发现H的下一个节点也全都走过了,所以退回到G,看G还有没有未走过下一个节点,发现没有了,再往回退,直到 G -> F -> E -> D,发现D有未走过下一个节点 I ,所以走 I

I走过后,发现也没有未走过的下一个节点了,所以继续往回退,D -> C -> B -> A,直到退回到根节点,整个遍历就结束了。

2. 代码

下面将贴出基于邻接表的深度优先遍历(DFS)算法,在这之前,我们先大致介绍一下邻接表

邻接表用一个链表节点的数组来存储所有节点,,并用链表来存储与当前节点邻接的所有节点,如下所示:
在这里插入图片描述
其中,第一行的ABCDEFGHI是一个数组,数组类型是ListNode(链表的节点),然后数组中的每个元素,都指向它自己的邻接点,就构成了上图中的邻接表

基于上述邻接表的存储方法,给出深度遍历的程序如下:

程序由另一篇博文中的程序改写而来。
原程序出自:CSDN博主【烟雨迷离半世殇】的博文数据结构篇:图的遍历(一:深度优先遍历)

int visited[G_numVertexes];//用一个visited数组来记录某个节点是否被遍历过:1表示遍历过;0表示没有遍历过。其中 ,G_numVertexes是图中节点的个数,也是邻接表中第一行那个数组的元素个数

void DFSTraverse(ListNode *G) {
    
    
    for (int i = 0; i < G_numVertexes; i++)
    {
    
    
        visited[i] = 0; //把visited数组的所有元素都初始化未0,表示都没遍历过
    }
    for (int i = 0; i < G_numVertexes; i++) //为了防止不连通图的特殊情况,在这里对每个节点都进行遍历
    {
    
    
        if (visited[i] == 0)
        {
    
    
            DFS(G, i); //对未遍历过的节点,调用DFS函数
        }
    }
}


void DFS(ListNode *G, int i) {
    
    
    EdgeNode *p;
    visited[i] = 1; //把这个节点的访问标志位设为1,表示已遍历过
    cout << G[i]->data << endl; //打印当前节点
    
    p = G[i]->adjvex; //根据邻接表的存储方式,把p设为G[i]的第一个邻接点
    while (p)
    {
    
    
    	cout << p->data << endl;
        if (!visted[p->adjvex]) //如果G[i]的另一个邻接点未遍历过,则遍历它
        {
    
    
            DFS(G, p->adjvex); //递归访问
        }
        p = p->next;
    }
}

二、广度优先遍历(BFS)

1. 理解

2. 代码

猜你喜欢

转载自blog.csdn.net/qq_39642978/article/details/112061940