全排列:
/*
* 递归输出序列的全排列
*/
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;
}