回溯法 DFS 全排列

回溯法求全排列

  最近在写算法老师布置的作业,其中有一道题是:有一个含有n个整数的数组a,所有元素均不相同,求其所有元素的全排列,例如,a[ ]={1,2,3},得到的结果是(1,2,3),(1,3,2),(2,3,1),(2,1,3),(3,1,2),(3,2,1)。题目很简单,但却很好的体现出了回溯法的思想,所以想借由这个题目来作为回溯法的典型,方便以后复习。(●’◡’●)
  解:显然本问题的解空间为排列树,直接用数组a生成其排列,每个位置可取a中任何元素,但一个排列中的元素不能重复。为此采用元素交换的方式,对排列数的第i层,扩展状态是a[ i ]位置可以取a[ i ]到a[ n-1 ]的任何元素,即j=i到n-1循环:将a[i]与a[ j ]交换,在这种方式下求出排列后需要恢复,即将a[ i ]与a[ j ]再次交换,回到交换之前的状态(回溯),然后继续求其他排列。
  例如a[ ]={1,2,3}时求全排列的过程如图5.8所示。
在这里插入图片描述

图中的树就是对应的解空间树,这里数组a的下标从0开始,所以根节点“a={1,2,3}”的层次为0,它的子树分别对应a[ 0 ]位置选择a[ 0 ]、a[ 1 ]、a[ 2 ]元素。实际上,对于第i层的节点,其子树分别对应a[ i ]位置选择a[ i ]、a[ i+1 ]、… 、a[ n-1 ]元素。树的高度为n+1,叶子结点的层次是n,解空间树更清晰的描述如图5.9所示。
在这里插入图片描述
  从图5.9中可以看出,对于第i层的结点,其扩展仅仅考虑a[ i ]及以后的元素,而不必考虑前面已经选择的元素。例如第2层的“1,3,2”结点,不必考虑前面的“1,3”仅仅扩展a[ 2 ],即a[ 2 ]取值为从根结点的路径上设有取过的值2,产生“1,3,2”的解。
  对应的Java代码如下:

public class FullArray_3 {
    static int[] a;
    static int n;

    //输入数组a的元素个数(数字的个数)以及对数组赋值(各个数字的值)
    public void inPut(){
        Scanner read = new Scanner(System.in);
        System.out.println("请输入数字的个数");
        n = read.nextInt();
        a = new int[n];
        System.out.println("请分别输入各个数字的值");
        for (int i =0;i<n;i++)
            a[i] = read.nextInt();
    }

    //通过深度优先来进行全排列
    public void dfs(int[] arr,int n,int i){
        if (i>=n)                //终结条件: 当交换到最底层所有元素都确定时做输出
            disPlay(arr,n);      
        else {                          //当没有达到最底层时,进行元素交换并递归
            for (int j =i;j<n;j++){
                swap(arr,j,i);
                dfs(arr,n,i+1);
                swap(arr,j,i);    //一个数组确定后需要回溯到上一个状态再进行然后求其他排列,所以需要将元素交换回来
            }
        }

    }
    
    //输出
    public void disPlay(int[] arr,int n ){
        for (int i =0;i<n-1;i++)
            System.out.print(arr[i]);
        System.out.println(arr[n-1]);
    }
    
    //元素交换
    public void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    
    public static void main(String[] args) {
        FullArray_3 f = new FullArray_3();
        f.inPut();
        f.dfs(a,n,0);
    }

}

  在代码的编写过程中,我在编写dfs方法的方法体时遗漏了esle关键字,导致方法在满足终结条件时仍进入了循环,因此线程一直存储dfs方法到栈堆中,从而使线程的堆栈大小超过分配的内存限制,发生StackOverFlowError。这提醒我们在编写程序时应该细心一点不能粗心大意。





           摆烂是形容有能力的人不作为,就我这两下子还摆啊,我不摆也很烂了/(ㄒoㄒ)/~~
在这里插入图片描述






  本文解中文字部分引用《算法与设计分析(第二版)》✨✨✨

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值