如果要求P(n,n),例如P(3,3)=3!=6,就使用本文章提到的全排列算法
如果要求P(n,m),例如P(5,2)=5!/(5-2)!=20,就先求C(n,m),然后对每一个组合求P(m,m)即可,因为P(n,m)=C(n,m)*P(m,m)
1.非递归实现 next_permutation
1.1 基本思想
注:此算法要求被排列的各个元素之间具有“Natural Order”,也就是说这些元素可以组成一个有序的序列,在JAVA中可以通过实现Comparable来完成
1.对初始队列进行排序,找到所有排列中最小的一个排列Pmin。
2.找到刚刚好比Pmin大比其它都小的排列P(min+1)。
3.循环执行第二步,直到找到一个最大的排列,算法结束。
例如排列ABCDE,这是所有排列中最小的一个排列,刚好比ABCDE大的排列是:ABCED。
1.2 算法描述
给定已知序列P = A1A2A3.....An
对P按字典排序,得到P的一个最小排列Pmin = A1A2A3....An ,满足Ai > A(i-1) (1 < i <= n)
从Pmin开始,找到刚好比Pmin大的一个排列P(min+1),再找到刚好比P(min+1)大的一个排列,如此重复。
1.从后向前(即从An->A1),找到第一对为升序的相邻元素,即Ai < A(i+1)。
若找不到这样的Ai,说明已经找到最后一个全排列,可以返回了。
2.从后向前,找到第一个比Ai大的数Aj,交换Ai和Aj。
3.将排列中A(i+1)A(i+2)....An这个序列的数逆序倒置,即An.....A(i+2)A(i+1)。因为由前面第1、2可以得知,A(i+1)>=A(i+2)>=.....>=An,这为一个升序序列,应将该序列逆序倒置,所得到的新排列才刚刚好比上个排列大。
4.重复步骤1-3,直到返回。
1.3 代码
/*Print the all-permutation of the given int array.*/
void next_permutation(int a[], intlength)
{if (length < 2)
{return;
}while (true)
{
print_array(a, length);//print the permutation
inti, j;for (i = length-2; i >= 0; --i)
{if (a[i] < a[i + 1])break;else if (i == 0)return;else;
}for (j = length-1; j > i; --j)
{if (a[j] >a[i])break;else;
}
swap(a, i, j);
reverse(a, i+ 1, length - 1);
}
}/*Reverse the elements between a[i] and a[j], inclusive.*/
void reverse(int a[], int i, intj)
{for (; i
{
swap(a, i, j);
}
}/*Swap two elements in an int array.*/
void swap(int *a, int i, intj)
{
a[j]^=a[i];
a[i]^=a[j];
a[j]^=a[i];
}/*Print an int array to the standard output stream.*/
void print_array(int a[], intlength)
{
std::cout<< "[";for (int i = 0; i < length-1; i++)
{
std::cout<< a[i] << ",";
}
std::cout<< a[length-1] << "]" <<:endl>
}
2.递归实现