数的全排列
数的全排列
一、介绍
从n个不同元素中任取m(m≤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位进行互换(也可以理解为第二位与自己互换过),依次类推到最后,进行所有情况的扩展。
浙公网安备 33010602011771号