Java全排列递归函数,1到5的所有不重复排列的次数,for循环调用递归函数的讲解

1.全排列

        就是一个数集的所有的排列,例如:12345它的全排列有12354,12435,13245等等,所有排列。

2.什么是子问题

        文字表达可能不太清楚,拿编程来说,函数其实就是一个子问题,也就是说递归函数没次调用一次,那么调用的这个函数就是一个子函数。

3.首先提供代码,然后是解释说明


import java.util.Arrays;

public class Main3 {
    static int flag = 0;//记录次数

    public static void main(String[] args) {
        int[] p = { 1, 2, 3, 4, 5 };//1~5数组

        Permutations(p, 0, p.length);//进行全排列的函数,每一个全排列函数就是一个子问题
        System.out.println(flag + "种");
    }
    /*
     * 输入p数组
     * start是子问题的开始位置
     * end是子问题的总长度
     */
    private static void Permutations(int[] p, int start, int end) {
        /*
         * 首先判断每个子问题是否到最后只剩自己和自己进行交换位置了
         * 如果是则是其中一个排列,直接输出
         */
        
        if (start == end) { 
            flag++;
            System.out.println(Arrays.toString(p));
            return;
        }

        for (int i = start; i < end; i++) {
            /*
             * 自己和自己交换位置或相邻交换位置
             * 当最后只剩下自己和自己交换位置时那么当前子问题将结束
             * 返回到上一个子问题
             * 
             */
            int temp = p[i]; 
            p[i] = p[start];
            p[start] = temp;
            Permutations(p, start + 1, end);
            /*
             * 每一个子问题结束时都要将交换后的排序还原到上一个子问题排序的样子
             * 这是为了不影响下一个子问题的交换排列
             */
            temp = p[i];
            p[i] = p[start];
            p[start] = temp;
        }
    }
}

运行结果

3.for循环的作用到底是什么意思,执行过程到底是什么

        很多朋友一直都没搞懂,这个for循环到底在做什么事情,其实这也困惑了我很久,最后做了几个算法题也算搞懂了。

举例子说明吧

if (start == end) { 
            flag++;
            System.out.println(Arrays.toString(p));
            return;
        }
for (int i = start; i < end; i++) {
            
            int temp = p[i]; 
            p[i] = p[start];
            p[start] = temp;
            Permutations(p, start + 1, end);
          
            temp = p[i];
            p[i] = p[start];
            p[start] = temp;
        }

上面代码数组[1,2,3,4,5]长度是5(end=5),假设start=0,从0开始,那么i也等于0,此时它自己和自己的元素交换位置,交换之后就会调用一次自身函数看看还有没有和后面的位置交换的可能,很显然是有的,因为start等于0,可以和start=1,start=2等进行位置交换,所以生成一个子问题将start+1的位置传过去,start+1就是start=0的一个子问题。

那么这时候start=1,i等于1开始,所以又和自身进行交换位置,继续生成一个子问题,那就是start=2,start=2又和自身所在元素交换位置生成一个子问题start=3,start=3又和自身所在元素交换位置生成一个子问题start=4,最后start=4又和自身所在元素交换位置生成一个子问题start=5,此时start=4的子问题start=5等于长度5,而start=4不能和start=5的元素交换位置,也就是说这个时候start=4只有一个子问题start=5了,而start等于5没有子问题了,那么直接结束start等于5的子问题,输出第一个排列[1,2,3,4,5],然后这个子问题结束后下面的位置交换是start=4和start=4的元素交换。

子问题start=5结束了,那么start=4的问题也结束了,那么就到解决start=3的问题了,i=start=3因为end=5,i<5的,然后i++,得到i=4,此时start=3和i=4的元素进行交换位置得到[1,2,3,5,4],交换完后start=3又调用函数生成一个子问题start=4,不过这一次的start=4解决的是排列[1,2,3,5,4],start = 4又生成最后一个子问题start= 5,然后直接输出[1,2,3,5,4],start=4问题又结束,继续回到问题start=3,此时i=4,start=3,i++,得到i=5,不满足i<5,子问题start=3结束,然后start=3和i=4交换位置,[1,2,3,5,4]还原数组为[1,2,3,4,5]

 问题start=3解决后,退回到解决它的上一个问题start=2,和上述操作一样,这里就不继续了,我们会发现,其实这个for循环就是在一个接着一个的产生一个相邻之间交换位置的子问题,子问题里再产生子问题,例如上面的假设i=start=0开始,会产生一个i=start=1的子问题,start=1的子问题又产生一个i=start=2的子问题,start=2的子问题又产生一个i=start=3的子问题,start=3的子问题又产生一个i=start=4的子问题,所以第一阶段i=start=0产生了start=1、start=2、start=3、start=4的子问题,接着,如果start=0的子问题全部解决后,就到i++,那么就是start=0的子问题中,i=1了,继续产生start=1、start=2、start=3、start=4的子问题,以此类推,时间不早了,可能说不太清楚,有机会图形结合再修改。

猜你喜欢

转载自blog.csdn.net/m0_59799878/article/details/129414092