深度优先搜索算法为什么不能用循环实现

题目描述
深度优先搜索遍历类似于树的先根遍历,是树的先根遍历的推广。其过程为:假设初始状态是图中所有顶点未曾被访问,则深度优先搜索可以从图中的某个顶点v出发,访问此顶点,然后依次从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作为起始点,重复上述过程,直至图中所有顶点都被访问到为止。其算法可以描述如下:
在本题中,读入一个无向图的邻接矩阵(即数组表示),建立无向图并按照以上描述中的算法遍历所有顶点,输出遍历顶点的顺序。
输入格式
输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。
以后的n行中每行有n个用空格隔开的整数0或1,对于第i行的第j个0或1,1表示第i个顶点和第j个顶点有直接连接,0表示没有直接连接。当i和j相等的时候,保证对应的整数为0。
输入保证邻接矩阵为对称矩阵,即输入的图一定是无向图。
输出格式
只有一行,包含n个整数,表示按照题目描述中的深度优先遍历算法遍历整个图的访问顶点顺序。每个整数后输出一个空格,并请注意行尾输出换行。
样例输入
4
0 1 0 1
1 0 0 0
0 0 0 1
1 0 1 0
样例输出
0 1 3 2

这是网上找的正确的深度优先搜索算法


#include<stdio.h>
#define maxint 32767
#define mvnum 100
typedef int vertextype;
typedef int arctype;
typedef struct{
    vertextype vexs[mvnum];
    
    arctype arcs[mvnum][mvnum];
    
    int vexnum;
}amgraph;
void creat(amgraph *G)
{
    scanf("%d",&G->vexnum);
    
    for(int i=0;i<G->vexnum;i++)
    {
        G->vexs[i]=i;
    }
    
    for(int i=0;i<G->vexnum;i++)
    for(int j=0;j<G->vexnum;j++)
    G->arcs[i][i]=maxint;
    
    for(int i=0;i<G->vexnum;i++)
    for(int j=0;j<G->vexnum;j++)
    scanf("%d",&G->arcs[i][j]);
 } 
int visited[mvnum]={0};
void DFS(amgraph G,int i)
{
    visited[i]=1;
    printf("%d ",G.vexs[i]);
    
    for(int j=0;j<G.vexnum;j++)
    {
        if(G.arcs[i][j]==1&&!visited[j])
        DFS(G,j);
    }
}
void DFStraverse(amgraph G)
{
    for(int i=0;i<G.vexnum;i++)
    {
        if(!visited[i])
        DFS(G,i);
    }
}
int main()
{
    amgraph G;
    creat(&G);
    DFStraverse(G);
    return 0;
}

这是我写的错误方法

#include<stdio.h>
#define max 10000
typedef struct{
    int dingdian[max];
    int guanxi[max][max];
    int dingdianshu;
}tu;
void creat(tu *t)
{
    scanf("%d",&t->dingdianshu);
    
    for(int i=0;i<t->dingdianshu;i++)
    {
        t->dingdian[i]=i;
    }
    
    for(int i=0;i<t->dingdianshu;i++)
    for(int j=0;j<t->dingdianshu;j++)
    scanf("%d",&t->guanxi[i][j]);
}
int visited[max]={0};
void DFS(tu t,int i)
{
    printf("%d",t.dingdian[i]);
    visited[i]=1;
    for(;i<t.dingdianshu;i++)
    for(int j=0;j<t.dingdianshu;j++)
    {
        if(t.guanxi[i][j]==1&&!visited[j])
        {
            i=j;
            DFS(t,i);
        }
    }
}
int main(void)
{
    tu t;
    creat(&t);
    int i=0;
    DFS(t,i);
    return 0;
}

为什么`使用循环实现深度优先搜索的时候程序会不能运行?

你的代码

for (; i < t.dingdianshu; i++)
    for (int j = 0; j < t.dingdianshu; j++)
    {
        if (t.guanxi[i][j] == 1 && !visited[j])
        {
            i = j;
            DFS(t, i);
        }
    }


感觉内循环里面有问题,i = j来更新i的值,循环条件就不满足了,递归调用后,外层的就会一直+,一直循环,死循环了。

该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
在深度优先搜索算法中,递归是实现的基础,因为它能够自然地模拟出搜索过程中的栈结构。而使用循环实现深度优先搜索则需要手动模拟出栈结构,这比较麻烦且容易出错。在你的代码中,使用了双重循环来模拟栈结构,但在遍历过程中没有对栈顶元素进行出栈操作,导致程序陷入了死循环,无法正常运行。

另外,你的代码中使用了一个不太规范的方式来遍历图,即通过遍历每个顶点的邻接矩阵来实现。这种方式可能不太适用于大规模的图,因为它需要将整个邻接矩阵都存储在内存中。在实际应用中,通常采用邻接表等数据结构来存储图,并使用深度优先搜索算法进行遍历。

综上所述,虽然可以使用循环来实现深度优先搜索算法,但这种方式不太适合于实际应用中的大规模图遍历,并且容易出错。正确的做法是使用递归来实现深度优先搜索,并根据具体情况进行优化。

以下是使用递归实现深度优先搜索的示例代码,假设图使用邻接表来存储:

import java.util.ArrayList;
import java.util.List;

class GraphNode {
    int val;
    List<GraphNode> neighbors;
    boolean visited;

    public GraphNode(int val) {
        this.val = val;
        this.neighbors = new ArrayList<>();
        this.visited = false;
    }
}

public class DFS {
    public void dfs(GraphNode node) {
        if (node == null || node.visited) {
            return;
        }

        // 标记当前节点已访问
        node.visited = true;

        // 输出当前节点值
        System.out.print(node.val + " ");

        // 递归遍历当前节点的所有邻居节点
        for (GraphNode neighbor : node.neighbors) {
            dfs(neighbor);
        }
    }
}

在这个示例代码中,GraphNode 表示图节点,包含节点值、邻居节点列表和访问标记三个成员变量。DFS 类实现了深度优先搜索算法,使用递归方式遍历图。在遍历过程中,对于每个节点,首先判断是否已经访问过,如果已经访问过则直接返回;否则将当前节点标记为已访问,并输出节点值。然后递归遍历当前节点的所有邻居节点,直到所有节点都被访问过为止。

这个示例代码中使用了递归方式实现深度优先搜索,这种方式简单、易于理解,而且能够自然地模拟出搜索过程中的栈结构。如果你需要对搜索算法进行优化,可以考虑使用迭代方式来实现深度优先搜索,或者使用其他数据结构来模拟栈结构。


如果以上回答对您有所帮助,点击一下采纳该答案~谢谢

  • 帮你找了个相似的问题, 你可以看下: https://ask.csdn.net/questions/7619927
  • 除此之外, 这篇博客: C语言实现八大排序算法详解及其性能之间的中的 我们老师给我们花了100个星星的重要,那就是非常重要,快速排序。名字就很嚣张。。。言归正传,快排采用了分治算法。把大问题,分解成小问题。首先我们先找一个基准值,基准值的寻找法,有很多,这里我先用一个取边上值得方法,找到基准值以后呢拿着这个基准值和所有数组比较,使这个数组中比基准值小的都放左边,比基准值大的都放到右边,然后就把原来数组分成三块,中间基准值,左边都是比它小的,右边都是比它大的。然后这两个数组,继续分,一直分。直到他的终止条件,也就是小数组有序了就停止,那么什么时候有序停止呢?小区间长度为1或者长度为0的时候,就是有序了。所有小数组都有序了,那么就是整个数组有序了。只是原理,那么问题,又来了,怎么放左放右呢?我目前会三种。 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 算法思想

  • 以下回答由chatgpt基于相关博客总结生成:

    深度优先搜索算法不能使用循环实现的原因是需要回溯到之前的节点,而循环在执行完之前一定会将所有节点遍历完,无法回溯。正确的实现是通过递归来实现深度优先搜索。

    代码如下:

    ```c

    define MAX_VERTEX_NUM 20

    typedef struct ArcNode{ int adjvex;