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); //交换,对应第六步
    
                }
            }
        }
    }
  • 相关阅读:
    Blender/UE4骨骼转换插件:Uefy v1.2.1 For UE4 BL 2.8+使用教程
    01【Daz模型】DazStudio 高品质可爱的小姐姐角色模型包 Lancy Character with dForce Hair and Expressions for Genesis 8 Female (含角色、头发、扩展)
    创作设计抖音免版权高清图库整理
    GPU三维地形生成软件 World Creator v2.1.0 Win
    [人物存档]【AI少女】【捏脸数据】【捏人数据】【人物卡】:女巫八重樱
    ubuntu Linux下C语言open函数打开或创建文件与read,write函数详细讲解
    OO第二次博客作业(第二单元总结)
    OO第一次博客作业(第一单元总结)
    Beta阶段 第四次Scrum Meeting
    Beta阶段 第三次Scrum Meeting
  • 原文地址:https://www.cnblogs.com/mynona/p/3731305.html
Copyright © 2011-2022 走看看