next_permutation在algorithm头文件里,可以用它来生成全排列。它的源代码加分析如下
template<class _BidIt> inline
bool _Next_permutation(_BidIt _First, _BidIt _Last)
{ // permute and test for pure ascending, using operator<
//-----------------------------------------------\
_DEBUG_RANGE(_First, _Last);
_BidIt _Next = _Last;
if (_First == _Last || _First == --_Next)
return (false);
//上面这一块是检查边界范围的
//-----------------------------------------------/
for (; ; )
{ // find rightmost element smaller than successor
_BidIt _Next1 = _Next;
if (_DEBUG_LT(*--_Next, *_Next1))
{ // swap with rightmost element that's smaller, flip suffix
_BidIt _Mid = _Last;
for (; !_DEBUG_LT(*_Next, *--_Mid); )
;
std::iter_swap(_Next, _Mid);
//本身带的注释已经说得很明白,从最右边开始比较两两相邻的元素,直至找到右边比左边大的一对,左边那个
//就是将要被替换的,再从最右边开始找比这个元素大的第一个,交换他们两个
std::reverse(_Next1, _Last);
//交换之后,翻转交换元素的后面的所有元素 (如1432->2134的过程,先交换1和2得到2431,再反转2后面的得到2134)
return (true);
}
if (_Next == _First)
{ // pure descending, flip all
std::reverse(_First, _Last);
return (false);
}
}
}
关键是确定一个排列的下一个排列是什么,我看着明白却说不明白,于是转贴一段,以下来自 http://www.cppblog.com/yindf/archive/2010/02/24/108312.html
abcd next_permutation -> abdc
那么,为什么abcd的下一个是abdc而不是acbd呢?
说简单一点,用 1,2,3,4 代替 a,b,c,d,可以得到:
原排列 中间转换 值
1,2,3,4 3,2,1 ((3 * (3) + 2) * (2) + 1) * (1) = 23
1,2,4,3 3,2,0 ((3 * (3) + 2) * (2) + 0) * (1) = 22
1,3,2,4 3,1,1 ((3 * (3) + 1) * (2) + 1) * (1) = 21
1,3,4,2 3,1,0 ((3 * (3) + 1) * (2) + 0) * (1) = 20
1,4,3,2 3,0,1 ((3 * (3) + 0) * (2) + 1) * (1) = 19
. . .
. . .
. . .
4,3,2,1 0,0,0 ((0 * (3) + 0) * (2) + 0) * (1) = 0
| | | | | |
| | | |
| |
上面的中间转换指的是:每一个数字后面比当前位数字大的数字的个数。比如:
1,3,4,2 中,1 后面有(3, 4, 2) 他们都大于1,所以第一位是 3
3 后面有(4, 2), 但只有4大于3,所以第二位是 1
4 后面有(2), 没有比4 大的,所以第三位是 0
最后一位后面肯定没有更大的,所以省略了一个0。
经过这种转换以后,就得到了一种表示方式(中间转换),这种表达方式和原排列一一对应,可以相互转化。
仔细观察这种中间表达方式,发现它的第一位只能是(0,1,2,3),第二位只能是(0,1,2),第三位只能是(0,1)。通常,数字是用十进制表示的,计算机中用二进制,但是现在,我用一种特殊的进制来表示数:
第一位用1进制,第二位用2进制。。。
于是就得到了这种中间表示方式的十进制值。如:
阶
| | |
1,1,0 ----> ((1 * (3) + 1) * (2) + 0) * (1) = 8
3,1,0 ----> ((3 * (3) + 1) * (2) + 0) * (1) = 20
这样,就可以得到一个十进制数和一个排列之间的一一对应的关系。
现在排列数和有序的十进制数有了一一对应的关系(通过改变对应关系,可以使十进制数升序)。