STL的<algorithm>算法库里面有好多可以省事的函数,如sort,steady_sort,swap之类的函数,next_permutation也是其中之一
一般来说我们是用这货给数组求全排列,可惜这货bug(其实也不算= =)略多,不可以有相同元素,要先排好序,要定义好比较(最好要给出绝对顺序,no偏序,也不是不行,但是会造成排列数量减少)。
例如
#include <iostream>
#include <algorithm>
int main()
{
int a[] = {1, 4, 1, 2};
int count = 0;
do
{
for(int i = 0; i < 4; i ++)
{
std::cout << a[i] << " ";
}
std::cout << std::endl;
count ++;
}while(std::next_permutation(a, a + 4));
std::cout << count << std::endl;
}
上述代码的输出只是
1 4 1 2
1 4 2 1
2 1 1 4
2 1 4 1
2 4 1 1
4 1 1 2
4 1 2 1
4 2 1 1
8
而其实next_permutation的实现还是比较容易的,利用的是推导的思想,即下一个排列是比当前排列大的集合中的最小排列(有点拗口。。)
具体思想是从后往前走,当出现下坡现象(如12346543在46处会出现下坡)时,可以确定4将会是被取代的值,原因在于4之后的部分是可以被确定的最大值(因为是倒序),这时应该从4之后找出比4大的最小数(即5),此时12346543会变成12356443,将5之后的所有元素按小值排序,变成12353446,此时就得到12346543的下一个排列12353446
具体代码如下
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
bool next_Permutation(int *arr, int size)
{
if(arr == NULL)
{
return false;
}
int j;
for(j = size - 2; j >= 0; j --)
{
if(arr[j + 1] > arr[j])
{
break;
}
}
if(j >= 0)
{
int target = j + 1;
for(int k = j + 1; k < size; k ++)
{
if(arr[k] > arr[j] && arr[k] < arr[target])
{
target = k;
}
}
std::swap(arr[j], arr[target]);
std::sort(arr + j + 1, arr + size);
return true;
}
else
{
return false;
}
}
而如果要得到全部的排列,首先要定义好元素的先序结构,进入循环前利用先序结构排好顺序,next_permutation也可以利用这个先序结构得到全部排列。
先序结构的定义不妨可以将元素本身及其下标组成结构体来联合定义。