zoukankan      html  css  js  c++  java
  • 深度优先搜索(DFS)递归形式改为非递归形式

    DFS将递归改为非递归这个方法的需求来自于一道三维积木组合的题目,还在苦苦调试中,暂且不提。

    普通的认识对于递归向非递归的转化无非是使用栈,但是结合到深度搜索如何将栈很好利用,如何很好保存现场,都不是很轻松(自身感觉)。

    网上大部分转化都是基于图的搜索进行,总是引出邻接点的概念,让人越看越迷,毕竟不是每个DFS都是图(不可否认都可以看成是图)。

    在众多资料中看到了CSDN上的一个转化方法很新颖(结构之法,算法之道):http://blog.csdn.net/v_july_v/article/details/6111353

    最后一点结合图提出了用队列栈来进行转化,由于伪代码和图有关,而且用到标志什么的,并没有细看,但是这个思想倒是启发了我。于是我决定使用这个思想进行转化尝试。

    全排列问题是一个典型的可利用DFS搜索出结果的题目,正巧我们学校的OJ上有这个题目的评测:http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1005

    于是使用队列栈来进行全排列,核心思想是:

    1.使用每一个队列表示深度搜索的同一层节点。

    2.栈的关系表示的是父亲和儿子的关系,不同层节点,且底部栈表示父亲节点,上层栈表示儿子节点

    整个非递归DFS过程如下:

    1.初始化最底层栈

    2.只要栈内还有队列继续循环(3-5):

    3.将栈顶队列弹出:

    4.判断栈顶队列是否为空,若为空,进行恢复现场操作,并且往回回溯,若不为空,将栈顶队列首元素出栈,为该元素生成下层节点,也为一个队列,然后将该元素作为已经遍历的一部分,记录到结果中。

    5.判断生成的队列是否为空,为空,说明已经到了搜索最底层,可输出相应的解,若不为空,将此队列入栈。

    这里有两个注意点:

    1.恢复现场操作有两处:一处在放置结果的时候,一处为栈顶队列为空的时候

    2.在第四步将栈顶队列首元素出栈之后,这个队列有可能为空,在这里不需要对这个队列进行和第5步类似的操作。因为有可能出现该节点为空,而儿子并不为空的情况。

     1 #include<iostream>
     2 #include<stack>
     3 #include<queue>
     4 using namespace std;
     5 int n;
     6 int ans[12];
     7 int visited[12]={0};
     8 typedef struct point{
     9     int num;
    10 }Point;
    11 stack< queue<Point> > mainstack;
    12 void DFS()
    13 {
    14     
    15     int cur=1;
    16     queue<Point> oneq;
    17     for(int i=1;i<=n;i++)
    18     {
    19         Point oneP;
    20         oneP.num=i;
    21         oneq.push(oneP);
    22     }
    23     mainstack.push(oneq);
    24     while(!mainstack.empty())
    25     {
    26         queue<Point> twoq;
    27         twoq=mainstack.top();mainstack.pop();
    28         if(!twoq.empty())
    29         {
    30             Point twoP=twoq.front();twoq.pop();
    31             int onenum=twoP.num;
    32             visited[ans[cur]]=0;//1.如果要修改则将当前置为可用
    33             ans[cur]=onenum;
    34             visited[onenum]=1;
    35             queue<Point> threeq;//该节点的子节点
    36             for(int i=1;i<=n;i++)
    37             {
    38                 if(visited[i]==0)
    39                 {
    40                     Point threep;
    41                     threep.num=i;//threep.flag=i;
    42                     threeq.push(threep);
    43                 }
    44             }
    45             //在这里直接加空判断,会出现本节点兄弟为空,儿子不为空的情况
    46             mainstack.push(twoq);
    47             //没有可扩展节点
    48             if(threeq.empty())
    49             {
    50                 for(int i=1;i<=n;i++)
    51                     cout<<ans[i]<<" ";
    52                 cout<<endl;
    53             }
    54             else
    55             {
    56                 mainstack.push(threeq);
    57                 cur++;
    58             }
    59         }
    60         else
    61         {
    62             visited[ans[cur]]=0;
    63             ans[cur]=0;//这里置0才能完全还原
    64             cur--;
    65         }
    66     }
    67 }
    68 int main()
    69 {
    70     cin>>n;
    71     DFS();
    72     return 0;
    73 }
    全排序非递归

    至于到全排序查重的地方,应该还有可以优化的地方,暂且不提,此代码在XOJ上提交通过。

    56 K
    1072 MS
    G++
    Apple
  • 相关阅读:
    log4j学习总结
    MAVEN工程生成可执行的jar包
    从svn上下载maven项目import cannot resolved
    junit4使用说明
    uml中箭头的意思
    maven命令
    mavenSvn
    ASP.NET MVC学习笔记:(二)return View(...)
    WPF学习笔记:(一)数据绑定与DataContext
    WCF学习笔记(五):svc、config和code文件之间的关系
  • 原文地址:https://www.cnblogs.com/holyprince/p/3482597.html
Copyright © 2011-2022 走看看