全排列問題
遞歸分析
•用一個數組a[n]來保存1n之間的n個自然數,對於i=1n,每次用a[1]與a[i]交換後,對a[2]~a[n]中的n-1個元素進行全排列
說明:大家輪流來做第1個 ,→ 循環 + 交換。確定好第1個後,對剩下的n-1個再進行全排列→遞歸
•然後交換a[1]與a[i]的值,使它恢復到此次排列前的狀態
已經做過第一個了,請回到原地,輪到下一個當第一個了。
確定好了第一個之後,從剩下的n-1箇中輪流選一個來做第2個 → 循環 + 交換 ,確定好了第二個之後,從剩下的n-2個再進行全排列。直到只有一個素的時候,全排列就是自己。
inline void perm(int list[], int k, int n)//求list數組 第k個到第n的全排列。
{
int i, t;
if (k == n)
{
for (i = 0; i <= n; i++)
{
printf("%d", list[i]);
}
printf("\n");
}
for (i = k; i <= n; i++)
{
swap(list[k], list[i]);
perm(list, k + 1, n); //求k+1~n的全排列
swap(list[k], list[i]);
}
}
字典序
全排列生成算法的一個重要思路,就是將集合A中的元素的排列,與某種順序建立一一映射的關係,按照這種順序,將集合的所有排列全部輸出。這種順序需要保證,既可以輸出全部的排列,又不能重複輸出某種排列,或者循環輸出一部分排列。字典序就是用此種思想輸出全排列的一種方式。這裏以A{1,2,3,4}來說明用字典序輸出全排列的方法。
首先,對於集合A的某種排列所形成的序列,字典序是比較序列大小的一種方式。以A{1,2,3,4}爲例,其所形成的排列1234<1243,比較的方法是從前到後依次比較兩個序列的對應元素,如果當前位置對應元素相同,則繼續比較下一個位置,直到第一個元素不同的位置爲止,元素值大的元素在字典序中就大於元素值小的元素。上面的a1[1…4]=1234和a2[1…4]=1243,對於i=1,i=2,兩序列的對應元素相等,但是當i=2時,有a1[2]=3<a2[2]=4,所以1234<1243。
使用字典序輸出全排列的思路是,首先輸出字典序最小的排列,然後輸出字典序次小的排列,……,最後輸出字典序最大的排列。這裏就涉及到一個問題,對於一個已知排列,如何求出其字典序中的下一個排列。這裏給出算法。
- 對於排列a[1…n],找到所有滿足a[k]<ak+1的k的最大值,如果這樣的k不存在,則說明當前排列已經是a的所有排列中字典序最大者,所有排列輸出完畢。
- 在a[k+1…n]中,尋找滿足這樣條件的元素l,使得在所有a[l]>a[k]的元素中,a[l]取得最小值。也就是說a[l]>a[k],但是小於所有其他大於a[k]的元素。
- 交換a[l]與a[k].
- 對於a[k+1…n],反轉該區間內元素的順序。也就是說a[k+1]與a[n]交換,a[k+2]與a[n-1]交換,……,這樣就得到了a[1…n]在字典序中的下一個排列。
int arry[3] = { 1,2,2 };//len==3;
//重複序列會去除
void Permutation()
{
int len = 3;
int j, k;
while (true)
{
printf("%d%d%d\n", arry[0], arry[1], arry[2]);
for (j = len - 2; j >= 0 && arry[j] >= arry[j + 1]; j--);//注意此處 j >= 0 判斷條件在前,加個等號即可
if (j < 0) return;//結束
for (k = len - 1; k > j&&arry[k] <= arry[j]; k--);//加個等號即可
swap(arry[k], arry[j]);
for (int l = j + 1, r = len - 1; l < r; l++, r--)
swap(arry[l], arry[r]);
}
}
從原理到應用
我們已經知道了實現原理,現在來說一下使用吧,
不知道大家是否還記得STL—“algorithm" 中的兩個函數next_permutation和prev_permutation
- next_permutation: 對於當前的排列,如果在字典序中還存在下一個排列,返回真,並且將下一個排列賦予當前排列,如果不存在,就把當前排列進行遞增排序。
- prev_permutation: 對於當前的排列,如果在字典序中還存在前一個排列,返回真,並且將前一個排列賦予當前排列,如果不存在,就把當前排列進行遞減排序。
#include<iostream>
#include<algorithm>
using namespace std;
int arry[3] = { 1,2,3 };//len==3;
void Permutation()
{
do
printf("%d%d%d\n", arry[0], arry[1], arry[2]);
while (next_permutation(arry, arry + 3));
}
int main()
{
Permutation();
return 0;
}