java 全排列非递归算法_全排列算法:递归和非递归实现

如果要求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.递归实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值