zoukankan      html  css  js  c++  java
  • 全排列算法(转)

    列出全排列的初始思想:

    解决一个算法问题,我比较习惯于从基本的想法做起,我们先回顾一下我们自己是如何写一组数的全排列的:1,3,5,9(为了方便,下面我都用数进行全排列而不是字符)。

    1,3,5,9.(第一个)

    首先保持第一个不变,对3,5,9进行全排列。

    同样地,我们先保持3不变,对5,9进行全排列。

    保持5不变,对9对进行全排列,由于9只有一个,它的排列只有一种:9。接下来5不能以5打头了,5,9相互交换,得到

    1,3,9,5.

    此时5,9的情况都写完了,不能以3打头了,得到

    1,5,3,9

    1,5,9,3

    1,9,3,5

    1,9,5,3

    这样,我们就得到了1开头的所有排列,这是我们一般的排列数生成的过程。再接着是以3、5、9打头,得到全排列。这里还要注意的一点是,对于我们人而言,我们脑子里相当于是储存了一张表示原有数组的表,1,3,5,9,1开头的所有排列完成后,我们选择3开头,3选完了之后,我们选择5开头,而不会再返过来选1,而且知道选到9之后结束,但对于计算机而言,我们得到了3,5,1,9后,可能再次跳到1当中,因为原来数组的顺序它已经不知道了,这样便产生了错误。对于算法的设计,我们也可以维护这样一个数组,它保存了原始的数据,这是一种方法同时我们还可以再每次交换后再交换回来,变回原来的数组,这样程序在遍历的时候便不会出错读者可以练习一下这个过程,思考一下你是如何进行全排列的,当然,你的方法可能和我的不太一样。

    我们把上面全排列的方法归纳一下,基本上就是:任意选一个数(一般从小到大或者从左到右)打头,对后面的n-1个数进行全排列。聪明的读者应该已经发现,这是一个递归的方法,因为要得到n-1个数的全排列,我们又要先去得到n-2个数的全排列,而出口是只有1个数的全排列,因为它只有1种,为它的本身。写成比较规范的流程:

    1.开始for循环。

    2.改变第一个元素为原始数组的第一个元素(什么都没做)。

    3.求第2个元素到第n个元素的全排列。

    4.要求第2个元素到第n个元素的全排列,要递归的求第3个元素到第n个元素的全排列。

    ......

    5.直到递归到第n个元素到第n元素的全排列,递归出口。

    6.将改变的数组变回。

    7.改变第一个元素为原始数组的第二个元素。

    (注:理论上来说第二次排列时才改变了第一个元素,即第6步应该此时才开始执行,但由于多执行一次无义的交换影响不大,而这样使得算法没有特殊情况,更容易读懂,如果一定要省时间可以把这步写在此处,这种算法我在下文中便不给出了,读者可以自己写。)

     

    5.求第2个元素到第n个元素的全排列。

    6.要求第2个元素到第n个元素的全排列,要递归的求第3个元素到第n个元素的全排列。

    ......

    5.直到递归到第n个元素到第n元素的全排列,递归出口。

    6.将改变的数组变回。

    ......

    8.不断地改变第一个元素,直至n次使for循环中止。

    为了实现上述过程,我们要先得到从第m个元素到第n个元素的排列的算法:

    从第m个元素到第n个元素的全排列的算法:

    public class Test {
    
        public static void main(String[] string) {
    
            int[] A = { 1, 2, 3 };
            Full_Array(A, 3);
    
        }
    
        static void Full_Array(int A[], int n) {
            Permutation2(A, 0, n);
        }
    
        static void swap(int[] a, int m, int i) {
            int temp = a[m];
            a[m] = a[i];
            a[i] = temp;
    
        }
    
        static void Permutation2(int a[], int m, int n) {
    
            Set set = new HashSet();
            if (m == n) {
                // Print(A); //直接输出,因为前n-1个数已经确定,递归到只有1个数。
                System.out.println(a);
                return;
            } else {
                for (int i = m; i < n; i++) // 进入for循环,对应第一步
                {
                    swap(a, m, i); // 交换,对应第二步
                    Permutation(a, m + 1, n); // 递归调用,对应三至五步
                    // swap(a, m, i); //交换,对应第六步
    
                }
            }
        }
    }
  • 相关阅读:
    MySql 主从
    MySql Docker 主主配置
    【算法刷题】C01-Q01 设计一个有getMin功能的栈
    redis管道技术pipeline二——api
    redis管道技术pipeline一 ——api
    Hbase结构和原理
    吴晓波:预见2021(跨年演讲 —— 02 “云上中国”初露峥嵘)
    吴晓波:预见2021(跨年演讲 —— 08 超级城市大赛鸣枪)
    吴晓波:预见2021(跨年演讲 —— 07 房产投资低空飞行)
    吴晓波:预见2021(跨年演讲 —— 06 购物中心即将消亡)
  • 原文地址:https://www.cnblogs.com/mynona/p/3731305.html
Copyright © 2011-2022 走看看