全排列的實現方法 字典序輸出

2021-08-09 04:30:54 字數 3067 閱讀 7459

一:背景

全排列在很多筆試都有應用,是乙個很常見的演算法,關於這類的題目變化很多。這種演算法的得到基於以下的分析思路。  給定乙個具有n個元素的集合(n>=1),要求輸出這個集合中元素的所有可能的排列。

例如:給定,全排列為3!個,即:,,

,下來分別說下遞迴法,字典序演算法來實現全排列。

二:實現演算法

1.遞迴法

遞迴的話就很簡單了,以為例,它的排列是:

以1開頭,後面接著的全排列,

以2開頭,後面接著的全排列,

以3開頭,後面接著的全排列。

**如下:

#include#includeusing namespace std;  

int arry[3] = ;

void recursion(int s, int t)

), printf("\n");

else

} }

int main()

方法二

#include #include#include#include#includeusing namespace std;

int arr[100];

void perm(int m,int n)

2.字典序演算法首先看什麼叫字典序,顧名思義就是按照字典的順序(a-z, 1-9)。以字典序為基礎,我們可以得出任意兩個數字串的大小。比如 "1" < "12"

如此,當我們知道當前的排列時,要獲取下乙個排列時,就可以範圍有序集合中的下乙個數(恰好比他大的)。比如,當前的排列時「123456879」, 那麼恰好比他大的下乙個排列就是「123456897」。 當當前的排列時最大的時候,說明所有的排列都找完了。

於是可以有下面計算下乙個排列的演算法:

設p是1~n的乙個全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn

1)從排列的右端開始,找出第乙個比右邊數字小的數字的序號j(j從左端開始計算),即 j=max(右邊的數從右至左是遞增的,因此k是所有大於pj的數字中序號最大者)

3)對換pi,pk

4)再將pj+1......pk-1pkpk+1......pn倒轉得到排列p'=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,這就是排列p的下乙個排列。

證明:

要證明這個演算法的正確性,我們只要證明生成的下乙個排序是恰好比當前排列大的乙個序列即可。圖1.11是從盧開澄老師的《組合數學》中擷取的乙個有1234生成所有排序的字典序樹。從左到右的每乙個根到葉子幾點的路徑就是乙個排列。下面我們將以這個圖為基礎,來證明上面演算法的正確性。

演算法步驟1,得到的子串 s = , 是按照從大到小進行排列的。即有 pj+1 > pj+2 > ... > pn, 因為 j=max;//len==3;

void permutation()

} int main()

方法二

#include#includeint n;

void fun(int a,int flag,int i,int ans)

;//len==3;

void permutation()

int main()

三:改進上面我們講了兩種方法來求解全排列,但是上面的問題是不可重複全排列,給出的初始序列各個元素互不相同,但是如果其中有相同的呢?結果會是如何?這個問題就是可重複全排列了。

我們知道對於乙個n個元素的序列(分別是n1,n2,n3,,,,nn),如果其中有k個元素相等,那麼這個序列的全排列個數就是 n!/k!。這是數學內容了,不做細講。

假如給出序列,用上述的遞迴和字典樹法求全排列:

對於遞迴:

明顯不對,有多個重複的排列。如何解決?

其實只要在交換元素之前判斷是否相等即可,改進**如下:

#include#includeusing namespace std;  

int arry[3] = ;

bool isequal(int s, int t)

void recursion(int s, int t)

), printf("\n");

else

} }

} int main()

輸出如下:

為什麼那樣判斷?舉個例子:對於 1abc2xyz2 這樣的排列,我們交換1與第乙個2,變成2abc1xyz2,按照遞迴的順序,接下來對abc1xyz2進行全排列;但是1是不能和第二個2交換的,如果交換了,變成了2abc2xyz1,按照遞迴的順序,接下來對abc2xyz1進行全排列,那麼問題來了,注意我紅色突出的兩個地方,這兩個全排列進行的都是同樣的工作,也就是如果1和第二個2交換必然會和前面重複。

同樣的對於字典序法,改進如下:

#include#includeusing namespace std;  

int arry[3] = ;//len==3;

void permutation()

} int main()

對於stl中的next_permutation呢?這就不需多慮了,stl裡已經把相同元素的情況考慮進去了,**不變。讀者可以自己試試。

字典序輸出全排列演算法

請編寫程式輸出前nnn個正整數的全排列 n 10n 10n 10 並通過9個測試用例 即nnn從1到9 觀察nnn逐步增大時程式的執行時間。輸入給出正整數nnn 10 10 10 輸出1到nnn的全排列。每種排列佔一行,數字間無空格。排列的輸出順序為字典序,即序列a1,a2,ana 1 a 2 a ...

全排列 字典序排列

include includeusing namespace std define dig num 4 void cal int str int first int last cout endl if first last bool get f l int list int former int l...

字典序全排列

思路 從左向右找到不符合遞增規律的第乙個數,比如1,2,5,4,3中的這個數就是2,將其與其右面遞增序列中的比他大的最小數,比如在前面例子中的3互換,得到1,3,5,4,2,最後,將該數右邊的遞增序列排序,得到1,3,2,4,5即可。上面這個是求某乙個數的下乙個排列,而全排列只需按這個思路,將初始陣...