在stl中有一个算法next_permutation用来生产全排列,要求是数组是升序排列好了的。
头文件#include <algorithm>
分析:
vs2008模板函数next_permutation实现如下
Code
1 // TEMPLATE FUNCTION next_permutation WITH PRED
2 template<class _BidIt,
3 class _Pr> inline
4 bool _Next_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred)
5 { // permute and test for pure ascending, using _Pred
6 _DEBUG_RANGE(_First, _Last);
7 _DEBUG_POINTER(_Pred);
8 _BidIt _Next = _Last;
9 if (_First == _Last || _First == --_Next)
10 return (false);
11
12 for (; ; )
13 { // find rightmost element smaller than successor
14 _BidIt _Next1 = _Next;
15 if (_DEBUG_LT_PRED(_Pred, *--_Next, *_Next1))
16 { // swap with rightmost element that's smaller, flip suffix
17 _BidIt _Mid = _Last;
18 for (; !_DEBUG_LT_PRED(_Pred, *_Next, *--_Mid); )
19 ;
20 std::iter_swap(_Next, _Mid);
21 std::reverse(_Next1, _Last);
22 return (true);
23 }
24
25 if (_Next == _First)
26 { // pure descending, flip all
27 std::reverse(_First, _Last);
28 return (false);
29 }
30 }
31 }
思路分析如下:
0,如果数组为空或者只有一个元素,直接返回false;
1,先找出数组最右的比右边已排序的最小的元素小的_Next。如果没有,则表示该序列是已经是完全降序排列的了,反序,使其成为降序序列,然后返回false.
2,找到在右边序列中降序排列时_Next元素的位置mid,交换_Next和mid指向的元素,那么右边得到一个新的以降序排列的序列。
3,反序_Next后面的序列,使其为升序;然后返回true;
参考:http://msdn.microsoft.com/en-us/library/tw245tyk.aspx.
自己实现非模板代码如下:
Code
bool next_permutation(int a[], int len)
{
if(len <=1||NULL==a)
return false;
int last = len - 1;
int next = last;
int next1;
for(;;)
{
next1 = next;
if(a[--next] < a[next1])//找到第一个比自己后面的元素小的元素,赋给next;
{
int mid = last+1;
while(a[next]>=a[--mid]);//找到右边序列(注意右边序列为降序排列)中最右边的大于自己的元素,将其位置赋给mid。
//交换a[mid]和a[next];右边得到一个新的降序排列的序列。
int temp = a[mid];
a[mid]=a[next];
a[next]=temp;
reverse<int*>(&a[next1],&a[last+1]);//反转右边的序列,使其升序排列。reverse为stl实现的反转算法。需要#include <algorithm>
return true;
}
if(next==0)
{
reverse<int*>(&a[0],&a[last+1]);
return false;
}
}
}