排列组合-按字典次序生成n!排列

//按字典次序生成集合的排列
//一个有n个不重复元素{123...n}的集合S,有n!个不同排列。
//他的最小排列是123...n,最大排列是n(n-1)...1
//S的字典次序排列是指从其最小排列123...n开始到最大排列n(n-1)...1为止,
//每一个当前排列比下一个排列小。
//生成集合S的字典次序的排列算法如下:
//1)将最小排列123...n作为当前排列
//2)从右向左找到第一个变换位置
//2.1)第一个变换位置的特点是它小于与其相邻的右边的元素,并且它右边的排列是它右边所有元素的最大排列。
//2.2)找到变换位置后,再在其右边所有比变换位元素大的元素中找到一个最小的元素,将这个最小元素与变换位元素交换。
//2.3)再将变换位右边的所有元素按升序排列,得到的这个新排列即是前面的当前排列的下一排列。
//3)如此反复,直到最后一个排列。

//生成P(n,r)的排列,可以先生成C(n,r)子集排列,然后对每个r子集进行P(r,r)排列。
public class Permutation
{
    public static void main(String[] args)
    {
        //指定集合的元素个数N
        int N=Integer.parseInt(args[0]);
        //使用一个长度为N的一维数组来表示这个排列
        int[] p=new int[N];
        //初值为123...n
        for(int i=0;i<p.length;i++)
            p[i]=i+1;
        show(p);
       //
        int i,j;
        int l,r;
        //当前排列不是最后一个排列时就继续生成下一个排列
        while(true)
        {
            //从右向左找第一个变换位i,特点是p[i]<p[i+1]
            for(i=N-2;i>=0 && p[i]>p[i+1];i--);
            //如果找不到变换位,说明当前排列已是最大排列,结束生成排列。
            if (i<0) break;
            //找到变换位后,在变换位的右边找比他大的最小元素这p[j](有p[j]=p[i]+1)
            for(j=N-1;j>i && p[i]>p[j];j--);
            //找到比变换元素p[i]大的最小元素p[j]后交换两元素
            exch (p,i,j);
            //变换位右边的元素按升序排列
            //在i,j元素交换前变换位右边的元素已是降序排列,i,j位置的元素交换后这个性质仍成立,所以右边的降序排列变更为升序排列时两端向中间交换即可得到
            l=i+1;
            r=N-1;
            while(l<r)
               exch(p,l++,r--);
            //显示排列   
            show(p);
        }
    }
  
    private static void exch(int[] a,int i,int j)
    {
        int temp=a[i];
        a[i]=a[j];
        a[j]=temp;
    }
    //显示这个数组中的值
    private static void show(int[] a)
    {
        for(int i=0;i<a.length;i++)
            StdOut.printf("%d",a[i]);
        StdOut.println();
    }
}

posted @ 2018-10-29 08:30  修电脑的龙生  阅读(526)  评论(0编辑  收藏  举报