深度优先搜索(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步类似的操作。因为有可能出现该节点为空,而儿子并不为空的情况。

深度优先搜索(DFS)递归形式改为非递归形式
 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

 

 

你可能感兴趣的:(DFS)