從n個不同元素中任取m(m≤n)個元素,按照一定的順序排列起來,叫做從n個不同元素中取出m個元素的一個排列。當m=n時所有的排列情況叫全排列。
公式:全排列數f(n)=n!(定義0!=1)
基本介紹
- 中文名:全排列
- 外文名:Full Permutation
- 解釋:組合數學術語
- 分類:數學
簡介
方法
字典序法





遞增進位制數法
遞減進位制數法
鄰位對換法
生成樹
生成樹中介數
全排列生成樹與生成樹中介數示意圖
全排列生成樹與生成樹中介數示意圖
全排列生成樹與生成樹中介數示意圖
全排列生成樹與生成樹中介數示意圖
算法完備性
計算排列數
遞歸
遞歸:
voidPerm(list[],intk,intm)//k表示前綴的位置,m是要排列的數目.{if(k==m-1)//前綴是最後一個位置,此時列印排列數.{for(inti=0;i<m;i++){printf("%d",list[i]);}printf("\n");}else{for(inti=k;i<m;i++){//交換前綴,使之產生下一個前綴.Swap(list[k],list[i]);Perm(list,k+1,m);//將前綴換回來,繼續做上一個的前綴排列.Swap(list[k],list[i]);}}}//此處為引用,交換函式.函式調用多,故定義為內聯函式.inlinevoidSwap(int&a,int&b){inttemp=a;a=b;b=temp;}非遞歸:
intb[N];intis_train(inta[],intn){inti,j,k=1;for(i=1;i<=n;i++){for(j=i+1;j<=n;j++)if(a[j]<a[i])b[k++]=a[j];/*判斷是否降序*/if(k>1)is_train(b,k);elsereturn(1);}}voidtrain(inta[],intn){inti,j,t,temp,count=1;t=1;printf("inputthe%3dthway:",count);for(i=1;i<=n;i++)printf("%3d",a[i]);printf("\n");while(t){i=n;j=i-1;/*從右往左找,找第一個左鄰比右鄰小的位置*/while(j&&a[j]>a[i]){j--;i--;}if(j==0)t=0;elset=1;if(t){i=n;/*從右往左找,找第一個比front大的位置*/while(a[j]>a[i])i--;temp=a[j],a[j]=a[i],a[i]=temp;quicksort(a,j+1,N);/*調用快速排序*//*判斷是否符合調度要求*/if(is_train(a,N)==1){count++;printf("inputthe%3dthway:",count);for(i=1;i<=n;i++)printf("%3d",a[i]);printf("n");}}}}Heap
Java
public class Test { public static char[] text = { 'a', 'b', 'c', 'd', 'e' }; public static void main(String[] args) { permutation(text, 0, text.length); System.exit(0); } /** * 全排列輸出 * * @param a[] 要輸出的字元數組 * @param m 輸出字元數組的起始位置 * @param n 輸出字元數組的長度 */ public static void permutation(char a[], int m, int n) { int i; char t; if (m < n - 1) { permutation(a, m + 1, n); for (i = m + 1; i < n; i++) { t = a[m]; a[m] = a[i]; a[i] = t; permutation(a, m + 1, n); t = a[m]; a[m] = a[i]; a[i] = t; } } else { printResult(a); } } /** * 輸出指定字元數組 * * @param text 將要輸出的字元數組 */ public static void printResult(char[] text) { for (int i = 0; i < text.length; i++) { System.out.print(text[i]); } System.out.println(); }}Pascal
var a:array[1..10000] of boolean; x:array[1..10000] of longint; n,i,total:longint;procedure print;{該過程用來列印輸出一次排列}var i:integer;begin for i:=1 to n do write(x[i],''); writeln; total:=total+1;{每列印一次累加一次,記住排列的個數}end;procedure try(i:integer);{調用的時候確定x[i]的值}var j:integer;begin for j:=1 to n do if a[j]=true then begin x[i]:=j; a[j]:=false;{某一個數被用過之後,在後面的遞歸調用中不能再用} if i<n{控制遞歸} then try(i+1){遞歸調用確定下一個數組元素x[i+1]的值} else print;{即出口,用於調用列印輸出一次排列} a[j]:=true;{下一次再選擇另一個數時釋放前面用過的數}{還原} end;end;begin total:=0;readln(n); for i:=1 to n do a[i]:=true; try(1);{首先應該確定的是數組x[1]中應該放置的數} writeln('total=',total);end.VB
OptionExplicit'修改:TZWSOHOPrivateSubCommand1_Click()DimntAsDouble:nt=TimerList1.Visible=False:List1.ClearPermutation"",Text1.TextList1.Visible=TrueDebug.PrintTimer-nt,EndSub
'遞歸求全排列'算法描述:'以8位為例,求8位數的全排列,其實是8位中任取一位'在後加上其餘7位的全排列'7位:任取一位,其後跟剩下6位的全排列'……'這樣就有兩部分,一部分為前面的已經取出來的串,另一部分為後面即將進行的全排列的串'參數pre即為前面已經取出來的串'參數str即為將要進行排列的串PrivateSubPermutation(preAsString,sAsString)DimiAsLong'//如果要排列的串長度為1,則返回IfLen(s)=1ThenList1.AddItempre&s:ExitSub'//for循環即是取出待排列的串的任一位Fori=1ToLen(s)'//遞歸,將取出的字元併入已經取出的串'//那么剩下的串即為待排列的串Permutationpre&Mid$(s,i,1),Left$(s,i-1)&Mid$(s,i+1)NextEndSub
C++實現
template<classType>voidPerm(Typelist[],intk,intm){//產生list[k:m]的所有全排列if(k==m){//只剩一個元素for(inti=0;i<=m;i++)cout<<list[i];cout<<endl;}else//還有多個元素待排列,遞歸產生排列for(inti=k;i<=m;i++)//循環交換第一個元素與其後的所有元素實現全//排列{Swap(list[k],list[i]);Perm(list,k+1,m);Swap(list[k],list[i]);}}我有一個非遞歸算法#include<stdio.h>int*n;voidarge(int*x,intsize){int*t;inttotoal=0;intpos=size-2;intjust=0;t=newint;for(inti=0;i<size;i++)t=1;while(1){for(i=0;i<size;i++)printf("%d",x);printf("\n");totoal++;pos=size-2;while(x[pos]>x[pos+1])//{pos--;t[x[pos+1]-1]=0;}if(pos<0)break;t[x[pos+1]-1]=0;//復位上一個t[x[pos]-1]=0;for(i=x[pos]+1;i<=size;i++){if(t[i-1]==0){x[pos]=i;t=1;break;}}t[x[pos]-1]=1;for(i=pos+1;i<size;i++){for(intj=1;j<=size;j++){if(t[j-1]==0){x=j;t[j-1]=1;break;}}}}printf("totoal=%d\n",totoal);delete[t];}intmain(){intm;scanf("%d",&m);n=newint[m];for(inti=0;i<m;i++)n=i+1;arge(n,m);delete[n];return0;}字典序法
#include<stdio.h>int*array;intnum;inlinevoidxchg(int&a,int&b){intc=a;a=b;b=c;}//從pos到num的數據進行翻轉voidinvert(intpos){intcount=num-pos+1;for(inti=0;i<count/2;i++)xchg(array[pos+i],array[num-i]);}//檢查輸入中是否有重複數值boolis_valid(intdata,intserial){for(inti=1;i<serial;i++)if(array[i]==data){printf("全排列中不能有數據重複!\n");return0;}return1;}//輸出全排列voidprint_permutation(intm){printf("之後第%d個全排列:",m);for(inti=1;i<=num;i++)printf("%d",array[i]);printf("\n");}//字典序全排列的主體voiddictionary(){printf("輸入起始的全排列:\n");for(inti=1;i<=num;i++){intdata;scanf("%d",&data);if(is_valid(data,i))array[i]=data;elsereturn;}if(num==1){printf("只有一個數,不需進行排列!\n");return;}intcount;printf("預測之後第幾個序列:\n");scanf("%d",&count);//一次循環找下一個全排列for(intm=1;m<=count;m++){intpos1=0;intpos2;//從num-1開始,找到第一個比右邊值小的位置for(intj=num-1;j>0;j--)if(array[j]<array[j+1]){pos1=j;break;}if(pos1<1||pos1>num){printf("目前全排列已為%d位數的最後一個全排列!\n\n",num);return;}//從num開始找array[pos1]小的第一個數的位置for(intn=num;n>pos1;n--)if(array[n]>array[pos1]){pos2=n;break;}xchg(array[pos1],array[pos2]);//從pos1+1到num的數進行翻轉invert(pos1+1);print_permutation(m);}}voidmain(){printf("輸入要進行全排列的位數\n");scanf("%d",&num);array=newint[num+1];while(1)dictionary();}JavaScript/AS3/TS鄰位對換法
var arr:Array = ["a", "b", "c", "d"];var d:int = arr.length;while (d--){ for (var i:int = 0, len:int = arr.length - 1; i < len; ++i) { var f1:String = arr[i + 1]; arr[i + 1] = arr[i]; arr[i] = f1; trace(arr); }}
