您的位置:首页 > 其它

全排列

2016-03-09 16:51 543 查看
参考于:【STL】next_permutation的原理和使用

给定一个数列,如何得到它的全排列?

例如1 2 3,它的全排列是123,132,213,231,312,321。

全排列的关键在于,给定某一数列,能从该数列推出“下一个”数列。

那么如何找“下一个”数列呢?

找“下一个”数列的算法思路描述如下:

1、从后往前找两个相邻元素,前一个位置记为i,后一个记为j,并且满足s[i] < s[j]
2、从后往前找另一个位置k,若满足s[i] < s[k],则将s[i]与s[k]交换,并将j之后(包括j)的所有元素颠倒排序,即得“下一个”数列。

先试着自己按照这个算法思路去模拟一下算法过程,看能不能悟出这个算法为什么是对的?如果还是不明白这个算法为什么是对的,再继续往下看。

举个例子,6 2 5 4 3 1,观察一下,下一个数列是6 3 1 2 4 5,回忆一下观察的过程,你是先从后往前找的对不对?你在找什么?

其实你在从后往前找,比较相邻两个数字,如果前一个数字比后一个数字大或相等,就继续往前找,直到找到前一个数字比后一个数字小,我们将前一个数字的位置记为i,后一个数字的位置记为j,此时应该满足s[i]<s[j]。这个例子中i = 1,j = 2。

可以看出从j开始的数列都是非升序排列的,因为刚刚在找的过程中,前一个数字都是比下一个数字大或相等。

要知道,非升序排列的数列不可能有“下一个”数列,即非升序排列的数列是“最大的”。那么从j开始的数列必定不存在“下一个”数列;另外一点,我们需要考虑i之前(不包括i)的数列吗?比如例子中的6,不需要!因为从i开始的数列必定存在“下一个”数列,因为它不是非升序排列的,非升序排列的数列必定存在“下一个”数列。所以结论是,我们只考虑从从i开始的数列找“下一个”数列。

从j开始的数列不可能有“下一个”数列,那么“下一个”数列的i位置放的值不能是原数,而应该从后面的数找,找比原数大的,然后这个数要尽量小。那么如何找到这个最小的数呢?因为从j开始的数列是非升序,所以从后往前找,找到比原数大的就行了。这个位置,我们记为k,例子中这个最小的数是3,即k=4。

找到k之后,交换i,k位置的值(一定可以找到这样的k,因为j位置就满足了)。交换之后,从j开始的数列依然是非升序排列。这个很明显,就不多解释了。

因为从j开始的数列是非升序排列,逆序一下,得到非降序排列,非降序排列是“最小的”。所以交换之后,从j开始,逆序排序一下,即得到“下一个”排列。

下面自己实现的源代码(原理同STL中的next_permutation)


View
Code

ps.理解源代码之后就可以知道为什么降序排列的数组,用STL中的next_permutation之后变成升序排列

最后再补充一个不规范的递归版本,所谓不规范,就是排列的顺序与STL中的next_permutation不一样。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: