DFS深度优先遍历算法练后反思(C++)

从经典情景来看,DFS算法很容易理解,虽然模拟起来很伤脑筋,但还是很容易明白其中的逻辑。DFS算法来遍历图时,需要一个vis[]数组用于记录结点是否已经被访问,然后顺着连接的点一直深度优先遍历过去即可。但是,我们应该思考一下,DFS算法的本质思想是什么,从而在解决其他具体问题时使用DFS算法的改编形式来更好地解决问题。本质就是借助递归手段完成深度优先的遍历。可以写出下面伪代码:

void DFS(){
    if(到达递归边界){ //也可能没有这一句,而由下面的循环条件直接判断了递归边界
        //可改编处
        return;
    }
    //可改编处
    while/for深度优先的条件{
        //可改编处
        操作;
    }
    //可改编处
    return;
}

于是,现在从源点s到目的点t之间有多条路径时,已知每个点的前一个点(用vector<int> pre[MAXN]存储),我们也可以借助DFS的思想来将所有路径存储在一个二维数组里(可以使用vector<vector<int> >,再用一个tempPath变长数组临时存放单条路径)。

可以写出下面核心代码:

void DFS(int t, int s){
    if(t == s){
        tempPath.push_back(t);
        path.push_back(tempPath);
        tempPath.pop_back();
        return;
    }

    tempPath.push_back(t); //*
    for(int i=0; i<pre[t].size(); i++){
        DFS(pre[t][i],s);  //*
    }
    tempPath.pop_back(); //*
}

以上面的代码为例,我们不需要每次使用DFS算法时都在脑子里模拟一遍计算机 执行DFS的流程,我们只需要知道什么时候可以使用DFS、怎么使用DFS、以及DFS中代码块不同位置会产生什么效果即可。

不过,我们现在还在可以来模拟一个上面代码的执行流程,给大家一个DFS运行的直观感受。

可以发现,我们只需要确定下面代码中语句1和语句2的作用即可:

DFS(...){
    递归边界
    语句1;
    DFS(...);
    语句2;
}

 它们分别在递归调用DFS之前和之后。

在递归调用DFS之前的语句,会随着递归不断入栈执行。在DFS之后的语句,会随着递归不断执行并退栈。也就是对于语句1与语句2之间循环的每一个DFS,都共用语句1和语句2,先语句1,然后把DFS看做一个已经封装好的解决好的相同子问题的答案,再结合语句2得到最终结果。说白了,DFS依然使用的是一个分治思想。

如上例,从目的点t开始找前点pre直到找到源点s,要得到的路径存在tempPath里,那么可以把问题分解为:               

语句1:(把t存到tempPath里),

DFS:(再把某一个pre[t]到源点s的路径存到tempPath里),

语句2:(再把t从tempPath里弹出)。

总而言之,假设调用一次DFS()我们就完成了我们需要的DFS的功能即可,在调用DFS()前后,我们只需实现一次DFS的功能,就能将全局问题利用递归分解为子问题层层解决。

不过这里要注意全局变量和函数内定义的变量的不同,全局变量在递归入栈时改变了,退栈时不会自动还原,需要手动还原,如这里的语句2:tempPath.pop_back(); 而函数体内定义的变量在递归出栈时会自动释放,同变量名变为外一层函数的变量值。

上面的DFS实现可以形象地说:目的点t来过tempPath数组,然后目的点前的某一点pre[t]到源点s的路径来过tempPath数组,然后又走了,然后t点也走了。注意目的点前的某一点pre[t]到源点s的路径相较于t点先来也先走,因为是调用的DFS的完整功能。

  • 18
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值