java 全排列非递归算法_全排列的非递归算法 - osc_ivkc73ze的个人空间 - OSCHINA - 中文开源技术交流社区...
1.全排列的定義和公式:
從n個(gè)數(shù)中選取m(m<=n)個(gè)數(shù)按照一定的順序進(jìn)行排成一個(gè)列,叫作從n個(gè)元素中取m個(gè)元素的一個(gè)排列。由排列的定義,顯然不同的順序是一個(gè)不同的排列。從n個(gè)元素中取m個(gè)元素的所有排列的個(gè)數(shù),稱為排列數(shù)。從n個(gè)元素取出n個(gè)元素的一個(gè)排列,稱為一個(gè)全排列。全排列的排列數(shù)公式為n!,通過(guò)乘法原理可以得到。
2.時(shí)間復(fù)雜度:
n個(gè)數(shù)(字符、對(duì)象)的全排列一共有n!種,所以全排列算法至少時(shí)間O(n!)的。如果要對(duì)全排列進(jìn)行輸出,那么輸出的時(shí)間要O(n?n!),因?yàn)槊恳粋€(gè)排列都有n個(gè)數(shù)據(jù)。所以實(shí)際上,全排列算法對(duì)大型的數(shù)據(jù)是無(wú)法處理的,而一般情況下也不會(huì)要求我們?nèi)ケ闅v一個(gè)大型數(shù)據(jù)的全排列。
3.列出全排列的初始思想:
解決一個(gè)算法問(wèn)題,我比較習(xí)慣于從基本的想法做起,我們先回顧一下我們自己是如何寫(xiě)一組數(shù)的全排列的:1,3,5,9(為了方便,下面我都用數(shù)進(jìn)行全排列而不是字符)。
【1,3,5,9】(第一個(gè))
首先保持第一個(gè)不變,對(duì)【3,5,9】進(jìn)行全排列。
同樣地,我們先保持3不變,對(duì)【5,9】進(jìn)行全排列。
保持5不變,對(duì)9對(duì)進(jìn)行全排列,由于9只有一個(gè),它的排列只有一種:9。
故排列為【1,3,5,9】
接下來(lái)5不能以5打頭了,5,9相互交換,得到
【1,3,9,5】
此時(shí)5,9的情況都寫(xiě)完了,不能以3打頭了,得到
1,5,3,9
1,5,9,3
1,9,3,5
1,9,5,3
這樣,我們就得到了1開(kāi)頭的所有排列,這是我們一般的排列數(shù)生成的過(guò)程。再接著是以3、5、9打頭,得到全排列。
我們現(xiàn)在做這樣的一個(gè)假設(shè),假設(shè)給定的一些序列中第一位都不相同,那么就可以認(rèn)定說(shuō)這些序列一定不是同一個(gè)序列,這是一個(gè)很顯然的問(wèn)題。有了上面的這一條結(jié)論,我們就可以同理得到如果在第一位相同,可是第二位不同,那么在這些序列中也一定都不是同一個(gè)序列。
那么,這個(gè)問(wèn)題可以這樣來(lái)看。對(duì)
T=【x1,x2,x3,x4,x5,........xn?1,xn】
我們獲得了在第一個(gè)位置上的所有情況之后(注:是所有的情況),對(duì)每一種情況,抽去序列T中的第一個(gè)位置,那么對(duì)于剩下的序列可以看成是一個(gè)全新的序列
T1=【x2,x3,x4,x5,........xn?1,xn】
序列T1可以認(rèn)為是與之前的序列毫無(wú)關(guān)聯(lián)了。同樣的,我們可以對(duì)這個(gè)T1進(jìn)行與T相同的操作,直到T中只一個(gè)元素為止。這樣我們就獲得了所有的可能性。所以很顯然,這是一個(gè)遞歸算法。
第一位的所有情況:無(wú)非是將x1與后面的所有數(shù)x2,x3,.......xn依次都交換一次
示意圖如下:
4.全排列的非去重遞歸算法
算法思路:全排列可以看做固定前i位,對(duì)第i+1位之后的再進(jìn)行全排列,比如固定第一位,后面跟著n-1位的全排列。那么解決n-1位元素的全排列就能解決n位元素的全排列了,這樣的設(shè)計(jì)很容易就能用遞歸實(shí)現(xiàn)。
【附代碼段:】
1 #include
2 using namespacestd;3 int arr[5]={0,1,2,3,4};4 void swap(int x,int y)//用于交換數(shù)組的兩個(gè)數(shù)
5 {6 int temp=arr[x];7 arr[x]=arr[y];8 arr[y]=temp;9 }10 int resove(int n)//遞歸函數(shù)
11 {12 if(n==5)//當(dāng)嘗試對(duì)不存在的數(shù)組元素進(jìn)行遞歸時(shí),標(biāo)明所有數(shù)已經(jīng)排列完成,輸出。
13 {14 for(int i=0;i<5;i++)15 cout<
20 {//i是從n開(kāi)始 i=n;swap(n,i)相當(dāng)于固定當(dāng)前位置,在進(jìn)行下一位的排列。
21 swap(n,i);22 resove(n+1);23 swap(n,i);24 }25
26 }27 intmain()28 {29 resove(0);30 }
排列模板
1 void permutation1(char* str,int sbegin,int send) //全排列的非去重遞歸算法
2 {3 if( sbegin == send) //當(dāng) sbegin = send時(shí)輸出
4 {5 for(int i = 0;i <= send; i++) //輸出一個(gè)排列
6 cout <
10 {11 for(int i = sbegin; i <= send; i++) //循環(huán)實(shí)現(xiàn)交換和sbegin + 1之后的全排列
12 {13 swap(str[i],str[sbegin]); //把第i個(gè)和第sbegin進(jìn)行交換
14 permutation1(str,sbegin + 1,send);15 swap(str[i],str[sbegin]); //【注1】交換回來(lái)
16 }17 }18 }
【注1】swap(str[i],str[sbegin])//交換回來(lái)
我們來(lái)仔細(xì)推敲一下循環(huán)體里的代碼,當(dāng)我們對(duì)序列進(jìn)行交換之后,就將交換后的序列除去第一個(gè)元素放入到下一次遞歸中去了,遞歸完成了再進(jìn)行下一次循環(huán)。這是某一次循環(huán)程序所做的工作,這里有一個(gè)問(wèn)題,那就是在進(jìn)入到下一次循環(huán)時(shí),序列是被改變了。可是,如果我們要假定第一位的所有可能性的話,那么,就必須是在建立在這些序列的初始狀態(tài)一致的情況下,所以每次交換后,要還原,確保初始狀態(tài)一致。
總結(jié)
以上是生活随笔為你收集整理的java 全排列非递归算法_全排列的非递归算法 - osc_ivkc73ze的个人空间 - OSCHINA - 中文开源技术交流社区...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java面试没过_Java面试中遇到的坑
- 下一篇: java去掉字符串中前后空格函数_JAV