通过分治思想递归实现数组的全排列

本文深入解析高中数学中排列与组合的概念,通过实例【1,2,3,4,5】展示5个数字的全排列计算过程,共120种排列方式。并提供一种分治递归算法实现全排列,适用于编程学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        在高中数学学习排列与组合的时候,我们知道,要得到一组元素的所有排列情况例如【1,2,3,4,5】这五个数字,它所有的排列一共有5!种,也就是5x4x3x2x1=120种。
        这是怎么得来的呢?我们是将它看作一个长度为5的序列,将每个位置上的可选元素的数目相乘得到的。例如,第一个数可以从1~5中选择,可选元素是5个,去掉第一位选中的元素,第二位可选元素有4个,以此类推,一共有120种排列方式。
        我们在编程中借鉴这个过程:数组第一个数和其他所有的数交换位置,可以得到数组第一个数可能出现的所有排列情况;然后先忽略掉数组第一位数字,将剩余数组视作一个新的数组,新数组的第一个数字再和其他所有数字交换位置,可以得到新数组第一个数可能出现的所有排列情况,以此类推,将一个数组分治为越来越小的数组,最后组合出来的排列,就是原数组的全排列。

/**
 * 分治递归实现全排列
 *
 * @author liuxiaofeng
 * @date 2018/10/24 13:32
 */
public class PermutationTest {

    /**
     * 记录排列数
     */
    private int count = 0;


    /**
     * 直接传入数组的重载方法
     *
     * @param arr 进行排列的数组
     */
    private void permutation(char[] arr) {
        permutation(arr, 0, arr.length - 1);
    }


    /**
     * 进行全排列的方法
     *
     * @param arr   字符数组
     * @param start 数组开始索引(分治子数组的起始索引)
     * @param end   数组末尾索引(为减少调用length方法次数,将末尾索引值静态化)
     */
    private void permutation(char[] arr, int start, int end) {
        if (start == end) {
            //排列完成,打印数组
            System.out.println("第 " + (++count) + " 个排列:" + Arrays.toString(arr));
        } else {
            for (int i = start; i < arr.length; i++) {
                //如果当前字符之前未出现过(非重复字符),和其他字符位置进行交换
                if (isUnique(arr, start, i)) {
                    //将当前字符与其他字符交换位置
                    swap(arr, start, i);

                    //将当前字符之后的部分视作新的数组(分治),对其进行排列
                    permutation(arr, start + 1, end);

                    //一次循环结束后还原字符位置,开始下一次循环
                    swap(arr, start, i);
                }
            }
        }
    }


    /**
     * 字符交换位置的方法
     *
     * @param arr    字符数组
     * @param index1 索引1
     * @param index2 索引2
     */
    private void swap(char[] arr, int index1, int index2) {
        char tmp = arr[index1];
        arr[index1] = arr[index2];
        arr[index2] = tmp;
    }


    /**
     * 判断当前字符是否已经出现过,出现过就是已经交换过,不再进行交换
     *
     * @param arr   字符数组
     * @param start 当前数组第一个字符的索引
     * @param curr  当前字符索引
     * @return 当前字符是否需要进行交换
     */
    private boolean isUnique(char[] arr, int start, int curr) {
        for (int i = start; i < curr; i++) {
            if (arr[curr] == arr[i]) {
                //当前字符已经出现过,返回false
                return false;
            }
        }
        return true;
    }


    /**
     * 测试方法
     */
    @Test
    public void test() {
        char[] arr = "1268133".toCharArray();
        permutation(arr);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值