全排列的演算法(四) n進制法

2021-06-28 15:51:59 字數 1757 閱讀 6189

n進制法

這個演算法是將初始排列012……(n-1)作為乙個n進製數,然後對它累加1,從而生成全體排列。這個演算法比較簡單,但是在累加過程中,會出現重複元素,所以需要將有重複元素的排列刪除。這是這個演算法的缺點。

從乙個排列生成乙個新的排列的演算法如下:

第一步:在排列的第n-1 位累加1。

第二步:如果其和大於n-1,就進製,發生連續進製就連續進製直至不再發生進製為止。無進製繼續。

第三步:檢查排列中有無重複元素,如果有則直接返回第一步;如果無則輸出乙個排列。

要產生n個元素的全排列,可以從原始排列01……(n-1)開始,對第n-1位累加

1,產生乙個新的排列後就輸出,然後返回重複以上步驟,直到排列的第乙個元素超過n-1時停止。 以3

個數0、1、2

的排列為例:原始排列是

1 2 3,從它開始,最後乙個元素是3,加上1則有

3+1=4,4>3,進製,前面乙個元素是2,進製後2+1=3,所以新排列是1 3 1,這個排列有重複元素,將它拋棄,繼續對最後乙個元素加

1,……。按照這個訪法,順序產生的排列是:1 2 3,1 3 2,1 3 3,2 1 1,2 1 2,2 1 3,2 2 1,2 2 2,2 2 3,2 3 1,2 3 2,2 3 3,3 1 1,3 1 2

,3 1 3,3 2 1

,3 2 2,3 2 3,3 3 1,3 3 2,3 3 3,4 1 1,這時第乙個元素大於3

,程式結束。把其中有重複元素的排列去掉,就得到了三個元素的排列。有下劃線的排列中存在重複元素,丟棄,餘下的就是全部排列。

需要注意,這裡並非嚴格意義的n進製數,因為每一項進製時是在該項大於n才發生。這樣做的目的是為了保證按照給定元素實現排列。

//n進製演算法

//輸入:排列元素個數n

//輸出:

n個元素的排列

#include

#include 

using namespace std;

void perm(int *p,int n);

void output(int *p,int n);

int repeat(int *p,int n);

int total;

int main()

freopen("in.dat","r",stdin);

int n,*p;

while(cin>>n)

p=new int[n];

for(inti0;i陣列初始化

p[i]=i+1;

total=0;

perm(p,n);

return 0;

void perm(int *p,int n)

while(1)

if(!repeat(p,n))           //排列中無重複元素

output(p,n);     //輸出乙個排列 

int i=n-1;               //在排列末尾累加1 

p[i]++;            

while(p[i]>n && i>0)    //有進製向前進製 

p[i--]-=n;

p[i]++;

if(p[0]>n)              //排列第一位大於n

return;       //結束 

void output(int *p,int n)

coutfor(int i=0;ifor(int j=i+1;jif(p[i]==p[j])

return 1;

return 0;

N個數的全排列

我採用的方法是類似密碼箱的轉輪來得到所有的排列組合 比如求 1,2,3,4的所有排列組合 採用遞減式輪轉來生成 n 4 以1234為初始值 得到如下的所有4個組合,放入最終的容器中 1 2 3 4 2 3 4 1 3 4 1 2 4 1 2 3 n 3 以上面的四個作為初始值,在第三位開始輪轉 得到...

N個數全排列的非遞迴演算法

n個數全排列的非遞迴演算法 include stdio.h voidswap int a,int b 根據當前的排列p,計算下乙個排列。原則是從1234 4321,若p已經是最後乙個排列,傳回false,否則傳回true。p是乙個n維向量。boolnextpermutation int p,intn...

全排列演算法的字典序排列

之前在中描述了全排列演算法的遞迴解法,這裡再說一種演算法 字典序排列。字典序排列就是按照字典a z,1 9的順序給出字串的順序全排列,例如abc的全排列就是從abc一直排到cba。那麼給定乙個字串,怎麼找出恰好大於該字串的下乙個排列呢?我們考慮如下的步驟 1 假設字串為p1p2 pn,我們從後往前尋...