数的全排列

数的全排列

 

一、介绍

  从n个不同元素中任取mm≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列

  当m=n时所有的排列情况叫全排列(Full Permutation)。公式:全排列数f(n)=n!(定义0!=1)。

  例如:现有3个不同元素 123,它的全排列为:1 2 3;1 3 2;2 1 3;2 3 1;3 1 2;3 2 1;全排列数为1*2*3=6。

 

二、算法

 

  现在要设计一段代码来完成对特定元素组的全排列

  1.如果是元素数很少的,我们可以通过多重循环嵌套枚举来完成;如3个不同元素123,用c语言进行三重循环:

 1 #include<stdio.h>
 2 
 3 int main(){
 4     int a,b,c;
 5     //三重嵌套,依次枚举第一位、第二位、第三位的元素 
 6     for(a=1;a<=3;a++)
 7         for(b=1;b<=3;b++)
 8             for(c=1;c<=3;c++)
 9                 if(a!=b && b!=c && c!=a){
10                     printf("%d %d %d\n",a,b,c);
11                 }
12     return 0;        
13 } 

  运行结果:

 

   同理,4个元素的1234的全排列,可以加上一层循环枚举;但是如果是像123456这样稍大一点的全排列,需要进行6层循环枚举,这样的算法就非常的麻烦了。

 

  2.

  我们知道,一段不重复的元素组如果以从小到大的升序排列(如 123),它只有一种排列(1 2 3 ),所以我们从第一位开始尽量的选取所能选取的最小数字,我们在第一个位置选择元素1,进入下一个位置,易得2是第二个位置所能选取的最小数字,故选择2,第3个元素自然是3了,此时3个位置都被我们依次填满了,获得了第一个排列 1 2 3 ;现在我们已经拥有了一种排列,如何获得全部的排列呢?

  当我们确定了第一位是1(可看成第一位与第一位进行了互换),就面临着第二位的选择,第一种排列里第二位是2,那么我们将第二位的2与第三位的3进行位置的互换,此刻我们又得到了一个新的排列 1 3 2;

  1开头的情况就完整了 ,为 1 2 3 ,1 3 2 ;

  但是我们不能立马进行下一轮的位置交换,我们需要先回溯,将第二位与第三位的位置再次互换, 得到了了1 2 3(1开头的最小排列);我们现在将第一位与第二位进行互换,得到了2 1 3(2开头的最小排列),再将第二位与第三位互换,得到了2 3 1;

  2开头的情况也完整了,为 2 1 3 ,2 3 1 ;

  同理,我们进行回溯,将第二位与第三位再次互换,得到 2 1 3(2开头的最小排列);此刻我们将第一位与第三位进行互换,得到了3 2 1(3开头的最小排序),再将第二位与第三位互换,得到了 3 2 1;

  那么3开头的情况也完整了,为 3 1 2, 3 2 1;

至此所有123的六种排列都完整了,1 2 3 ,1 3 2 ,2 1 3 ,2 3 1, 3 1 2 ,3 2 1;

  扩展到n元素呢?

  下面是JAVA代码:

 1 import java.util.Scanner;
 2 
 3 public class Permutation {
 4     
 5     public static int cnt = 0;//定义一个计数器来记录排列次数    
 6     public static void main(String []args) {
 7         Scanner reader = new Scanner(System.in);
 8         int []num = new int[reader.nextInt()];
 9         for(int i=0;i<num.length;i++) {
10             num[i] = i+1;
11         }
12         Sort(0,num,num.length);
13         System.out.println("共排列"+cnt+"次。");
14     }
15     public static void Sort(int a,int []n,int length) {//a数组起始位置,n为原始数组,length数组长度
16         
17         if(a==length) {//结束
18             print(n);
19             cnt++;
20         }
21         else {
22             for(int i=a;i<length;i++) {
23                 int temp;
24                 temp = n[i];
25                 n[i] = n[a];
26                 n[a] = temp;
27                 Sort(a+1,n,length);//前进一位        
28                 //回溯
29                 temp = n[i];
30                 n[i] = n[a];
31                 n[a] = temp;
32             }
33         }
34     }
35 
36     public static void print(int []n) {//输出一种排列
37         for (int i=0;i<n.length;i++){
38           System.out.print(n[i]+" ");
39         }
40         System.out.println();
41     }
42 }

  输入3的运行结果:

 

 

 

  如果我们不进行回溯会发生什么呢? 

 

 

 总结:对于n元素的全排列问题,我们先考虑第一位,一共有n个元素,第一位自然就有n种情况,所以我们需要考虑1开头、2开头...n开头的各种情况,而我们确定初始排列为123...n这样的升序排列之后,我们用第一位依次与第二位、第三位、第n位进行互换(也可以理解为第一位与自己互换过),这是第一位的所有情况;那么第二位的所有情况同理,第二位依次与第三位、第四位、...第n位进行互换(也可以理解为第二位与自己互换过),依次类推到最后,进行所有情况的扩展。

 

 

 

 

 

posted on 2020-03-26 22:38  SilviaM  阅读(484)  评论(1)    收藏  举报