DFS实现数字排列-java

DFS叫做深度优先搜索算法,我们通过DFS来实现数字的全排列。

 

前言

DFS叫做深度优先搜索算法,我们通过DFS来实现数字的全排列。

一、DFS是什么?

1.算法思路

DFS又叫做深度优先搜索算法。一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。

2.模拟演示

我们用一棵树来模拟一下深度优先搜索的过程,我们用数字来标识每一个结点。

0fa8834eebc34646beb7a724e25b06eb.png

图2.1 树

用DFS搜索从根结点1开始沿着树的深度进行搜索。1->2->4,当搜索到底部时,我们进行回溯,即4->2->5 ,然后重复上述操作,这就是一个简单的深度优先搜索的过程。整个搜索过程如下:

1->2->4->2->5->2->6->2->1->3->7->3->8->3->9->3->1。至此结束。

DFS我们通常会通过使用stack(栈)这种数据结构来实现。

注:栈的特点先进后出。

二、排列数字

1.排列数字

给定一个整数n,我们把1-n排成一排,那么我们可以得到很多种排列方法,最后我们按照字典序的方式排列出所有方法。如图所示:

20225bf4c91c41c3b43d11874c4b9577.png

 图1.1 排列数字3

 2.DFS模拟过程

656ba59d6c41428399ff06fbde0eb069.png

图2.1DFS模拟过程 

假设有 3 个空位,从前往后填数字,每次填一个位置,填的数字不能和前面一样。

最开始的时候,三个空位都是空的: _ _ _

首先填写第一个空位,第一个空位可以填 1,填写后为:1_ _

填好第一个空位,填第二个空位,第二个空位可以填 2,填写后为:1 2 _

填好第二个空位,填第三个空位,第三个空位可以填 3,填写后为: 1 2 3

 所以这是一种方案

然后往后退一步,退到了状态:1 2 _ 。剩余第三个空位没有填数。第三个空位上除了填过的 3 ,没有其他数字可以填。

因此再往后退一步,退到了状态:1_ _ 。第二个空位上除了填过的 2,还可以填 3。第二个空位上填写 3,填写后为:1 3 _

填好第二个空位,填第三个空位,第三个空位可以填 2,填写后为: 1 3 2

所以这是一种方案,输出。

然后往后退一步,退到了状态:1 3 _ 。剩余第三个空位没有填数。第三个空位上除了填过的 2,没有其他数字可以填。

因此再往后退一步,退到了状态:1_ _ 。第二个空位上除了填过的 2,3,没有其他数字可以填。

因此再往后退一步,退到了状态: 。第一个空位上除了填过的 1,还可以填 2。第一个空位上填写 2,填写后为:2 _ _

填好第一个空位,填第二个空位,第二个空位可以填 1,填写后为:2 1 _

填好第二个空位,填第三个空位,第三个空位可以填 3,填写后为:2 1 3

这时候,空位填完,无法继续填数,所以这是一种方案,输出。

然后往后退一步,退到了状态:2 1 _ 。剩余第三个空位没有填数。第三个空位上除了填过的 3,没有其他数字可以填。

因此再往后退一步,退到了状态:2_ _ 。第二个空位上除了填过的 1,还可以填 3。第二个空位上填写 3,填写后为:2 3 _

填好第二个空位,填第三个空位,第三个空位可以填 1,填写后为:2 3 1

这时候,空位填完,无法继续填数,所以这是一种方案,输出。

后退一步,退到了状态:2 3 _ 。剩余第三个空位没有填数。第三个空位上除了填过的 1,没有其他数字可以填。

再往后退一步,退到了状态:2_ _ 。第二个空位上除了填过的 1、3,没有其他数字可以填。

因此再往后退一步,退到了状态:_ _ _ 。第一个空位上除了填过的 1、2,还可以填 3。第一个空位上填写 3,填写后为:3 _ _

填好第一个空位,填第二个空位,第二个空位可以填 1,填写后为:3 1 _

填好第二个空位,填第三个空位,第三个空位可以填 2,填写后为:3 1 2

这时候,空位填完,无法继续填数,所以这是一种方案,输出。

然后往后退一步,退到了状态:3 1 _ 。剩余第三个空位没有填数。第三个空位上除了填过的 2,没有其他数字可以填。

因此再往后退一步,退到了状态:3_ _ 。第二个空位上除了填过的 1,还可以填 2。第二个空位上填写 2,填写后为:3 2 _

填好第二个空位,填第三个空位,第三个空位可以填 1,填写后为:3 2 1

这时候,空位填完,无法继续填数,所以这是一种方案,输出。

然后往后退一步,退到了状态:3 2 _ 。剩余第三个空位没有填数。第三个空位上除了填过的 1,2,没有其他数字可以填。

因此再往后退一步,退到了状态:3 _ _。第二个空位上除了填过的 1、2,没有其他数字可以填。

因此再往后退一步,退到了状态: _ _ _。第一个空位上除了填过的 1、2、3,没有其他数字可以填。

至此深度优先搜索结束,全部过程排列完毕。

三、代码如下



import java.io.*;

public class 数字排列 {
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    //保存每一次路径
    static int[] path;
    //记录数字的状态,即是否被访问过
    static boolean[] flag;
    static int n;
    public static void main(String[] args) throws Exception{
        n = nextInt();
        path = new int[n+1];
        flag = new boolean[n+1];
        dfs(0);
        pw.flush();
    }
    //我们通过u来判断是否是叶子节点 u=0是在第一层 u=1是在第二层
    public static void dfs(int u) {
        //u==n时就说明我们已经彻底结束了 ,因为我们传参是从0开始的,可以结合图2.1来看
        if(u == n){
            for(int i = 0;i < n;i++){
                pw.print(path[i]);
            }
            pw.println();
            return;
        }
        //n层循环,相当于我们把每一个当第一位处理的每一种情况
        for(int i = 1;i <= n;i++){
            //我们来判断当前数字是否被处理过 比如我们第一个数字是1 那么后面两位就不能是1
            if(!flag[i]){
                path[u] = i;
                flag[i] = true;
                //相当于我们递归地处理后一个位置的数字
                dfs(u+1);
                //找寻完后,我们需要把所有的数字状态全部恢复
                flag[i] = false;
            }
        }
    }
    public static int nextInt()throws Exception{
        st.nextToken();
        return (int)st.nval;
    }
}

1.读入数据

3

2.代码运行结果

123
132
213
231
312
321

总结

DFS深度优先搜索算法我们主要还是通过递归来实现的,但是递归的代码量虽然少,但是需要我们仔细的理解递归函数的每一步,熟悉我们搜索的每一步都是干什么的,想要理解透彻的话建议自己按着代码一步一步的debug一遍,加深一下理解。

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值