將排列(abcdef)應用(cdfbea),那麼它的逆爲(cdfbea)應用(abcdef)等價於(abcdef)應用(fdabec)算法
因此(cdfbea)的逆爲(fdabec)ide
E1.獲取當前的替代X,X[i]表示i被X[i]代替,將m從1到n遍歷(所有遍歷,與起始點無關),設j爲任意負值.spa
E2.獲取當前的i=X[m],若是當前X[m]<0,則X[m]取自身相反數,去E5.code
E3.當前X[m]大於0,X[m]=j,j=-m,m=i,i=X[m].blog
E4.i>0,則回E3;不然將X[m]=-j;io
E5.m自增長1.若是m>n,算法結束.event
某排列的逆能夠分爲1~n個部分,每一個部分能夠看做一個環.經過遍歷,對於每一個點所在的環,要麼已經遍歷過要麼沒有遍歷過,對於沒有遍歷過的,一開始這個環上的某個節點會得到一個任意的負值(j),而後將當前的-m賦給X[X[m]],因爲是環路最終必定存在X[X[m]]=j。而這個過程當中全部-m均賦值給X[X[m]],只有最後一個-m沒有賦值,而剛好這個-m是咱們一開始遍歷這個環的某個節點的最終值,同時在這個過程當中,這個環路上其餘的節點都已經賦過值,所以對於沒有遍歷過的環上的節點只要先處理一個節點,其餘節點的值就會隨之計算出來。class
void PermutationInvertingA(char *SrcStr) { int m,Len,i,j; Len=strlen(SrcStr); int *X=(int *)malloc((Len+1)*sizeof(int)); for(i=0;i<Len;++i) { X[i+1]=SrcStr[i]-'a'+1; } for(m=1,j=-1;m<=Len;++m) { i=X[m]; if(i<0) { X[m]=-i; continue; } if(i==m) { continue; } while(i>0) { X[m]=j; j=-m; m=i; i=X[m]; } X[m]=-j; } for(i=1;i<=Len;++i) { printf("%d ",X[i]); } printf("\n"); free(X); }
E1.獲取當前的X[i],X[i]表示i要被X[i]代替,而後將全部的X[i]=-X[i],將m從1到n開始遍歷(所有遍歷,與起始點無關)cli
E2.將m賦給jsed
E3.i=X[j],若是i>0,將j=i,重複E3.
E4.X[j]=X[-i],X[-i]=m
E5.m自增長1,若是m>n算法結束
撤銷操做不一樣環之間的操做是不影響,因此咱們只須要看一個環就行,假設當前X[i](1<=i<=n)爲
X[1]=-3,X[2]=-1,X[3]=-4,X[4]=-2(環爲1->3->4->2->1)
具體流程就爲:
將1指向的操做撤銷,將X[3]原值賦給X[1],X[3]=1
獲得X[1]=-4,X[2]=-1,X[3]=1,X[4]=-2
將2指向的操做撤銷,X[2]=-4,X[1]=2
獲得X[1]=2,X[2]=-4,X[3]=1,X[4]=-2
將3指向的操做撤銷,因爲當前X[3]爲正數,根據X[3]當前的值找到了X[1],由於X[3]的原值賦給了X[1],而後有找到了X[2],就有X[2]=-2,X[4]=3
獲得X[1]=2,X[2]=-2,X[3]=1,X[4]=3
將4指向的操做撤銷,先找X[4],而後找X[3],而後找X[1],而後找X[2],就有X[2]=-2,X[2]=4
獲得X[1]=2,X[2]=4,X[3]=1,X[4]=3
算法每一次是爲了撤銷當前的數指向的操做,而後逐步構造出最終的圖(排列)
void PermutationInvertingB(char *SrcStr) { int m,Len,i,j; Len=strlen(SrcStr); int *X=(int *)malloc((Len+1)*sizeof(int)); for(i=0;i<Len;++i) { X[i+1]=-(SrcStr[i]-'a'+1); } for(m=0;m<=Len;++m) { j=m; while(i=X[j],i>0) { j=i; } X[j]=X[-i]; X[-i]=m; } for(i=1;i<=Len;++i) { printf("%d ",X[i]); } printf("\n"); free(X); }