全排列:
/*
* 遞歸輸出序列的全排列
*/
void FullArray(char* array, size_t array_size, unsigned int index)
{
if(index >= array_size)
{
for(unsigned int i = 0; i < array_size; ++i)
{
cout << array[i] << ' ';
}
cout << '\n';
return;
}
for(unsigned int i = index; i < array_size; ++i)
{
swap(array, i, index);
FullArray1(array, array_size, index + 1);
swap(array, i, index);
}
}
字典序:
使用字典序輸出全排列的思路是,首先輸出字典序最小的排列,然後輸出字典序次小的排列,……,最後輸出字典序最大的排列。這裏就涉及到一個問題,對於一個已知排列,如何求出其字典序中的下一個排列。這裏給出算法。
對於排列a[1…n],找到所有滿足
a[k]<a[k+1](0<k<n-1)
的k的最大值,如果這樣的k不存在,則說明當前排列已經是a的所有排列中字典序最大者,所有排列輸出完畢。在a[k+1…n]中,尋找滿足這樣條件的元素l,使得在所有a[l]>a[k]的元素中,a[l]取得最小值。也就是說a[l]>a[k],但是小於所有其他大於a[k]的元素,如果有相同的a[l],取最後的一個。
交換a[l]與a[k].對於a[k+1…n],反轉該區間內元素的順序。也就是說a[k+1]與a[n]交換,a[k+2]與a[n-1]交換,……,這樣就得到了a[1…n]在字典序中的下一個排列。
這裏我們以排列a[1…8]=13876542爲例,來解釋一下上述算法。首先我們發現,1(38)76542,括號位置是第一處滿足a[k]<a[k+1]
的位置,此時k=2。所以我們在a[3…8]的區間內尋找比a[2]=3大的最小元素,找到a[7]=4滿足條件,交換a[2]和a[7]得到新排列14876532,對於此排列的3~8區間,反轉該區間的元素,將a[3]-a[8],a[4]-a[7],a[5]-a[6]分別交換,就得到了13876542字典序的下一個元素14235678。下面是該算法的實現代碼
#include <iostream>
#include <vector>
#include <limits.h>
#include <algorithm>
using namespace std;
vector<int> NextDic(vector<int>& vec)
{
vector<int> next(vec);
int last_(0);
for (int i = next.size()-1; i >= 1;--i)
{
if (vec[i] > vec[i - 1])
{
last_ = i-1;
break;
}
}
if (last_ == 0&&vec[last_]>=vec[last_+1])
{
next.clear();
return next;
}
int first_big_index(last_+1);
for (auto i = first_big_index; i < vec.size();++i)
{
if (vec[i]>vec[last_]&& vec[i]<=vec[first_big_index] )
{
first_big_index = i;
}
}
swap(next[last_], next[first_big_index]);
int left = last_ + 1, right = next.size() - 1;
while (left <right)
{
swap(next[left], next[right]);
left++;
right--;
}
return next;
}
void func(vector<int> & vec)
{
sort(vec.begin(), vec.end());
vector<int> next = vec;
while (!next.empty())
{
for (auto i = 0; i < next.size();++i)
{
cout << next[i] << " ";
}
cout << endl;
next = NextDic(next);
}
}
int main()
{
vector<int> vec{ 2, 1, 2 };
func(vec);
return 0;
}