全排序

来源:互联网 发布:网络直销是是骗局吗 编辑:程序博客网 时间:2024/04/28 00:19

void permute(const string & str, int low, int high)
{
  vector<char> cVec;
  for(; low < high; ++low)
     cVec.push_back(str[low]);
  do{
      copy(cVec.begin(), cVec.end(), ostream_iterator<char>(cout,""));
     cout<<endl;
  }while(next_permutation(cVec.begin(), cVec.end()));
}


// TEMPLATE FUNCTION next_permutation
template<class _BI> inline
    bool next_permutation(_BI _F, _BI _L)
    {_BI _I = _L;
    if (_F == _L || _F == --_I)  // (1)
        return (false);
    for (; ; )
        {_BI _Ip = _I;  // (2)
        if (*--_I < *_Ip)   // (3)
            {_BI _J = _L;
            for (; !(*_I < *--_J); )  // (4)
                ;
            iter_swap(_I, _J);  // (5)
            reverse(_Ip, _L);  // (6)
            return (true); }
        if (_I == _F)
            {reverse(_F, _L);  // (7)
            return (false); }}}

next_permutation()将[first,last)标记的排列重排为下一个排列,如果不存在下一个排列,则返回false。
源码分析(假设有容器{3,5,4,2}):
(1)、由于范型算法一般是应用在容器上,而容器是用其首元素和最后元素的下一个位置来表示其范围的,所以next_permutation()处理的 [first,last)为半开半闭区间,对于算法内部,则很明显要先对_I进行递减操作,使其指向容器的最后一个元素,如果和首元素地址相同,则为单元素容器,不存在下一个排列。
(2)、把_I的iter赋给_lp,注意对于第一次循环_I是指向最后元素了(因为(1)中有操作--I)。_Ip和_I指向容器元素5时,(3)的条件满足。
(3)、因其处在无限循环for(;;)中,故在容器中从后往前找第一个非逆序(后面的元素不小于其紧挨的之前的元素*--I<*_lp)(3,5),此时_I指向3,_lp指向5。
(4)、对_I到最后一个元素之间的元素查询是否有大于_I所指向的元素(3),有!此时_J指向元素5大于3。如果没有,那么该for循环最后_I,_J指向同一元素3,同样结束该for循环。
(5)、交换_I,_J所指向的元素。得到容器{4532}
(6)、对于_lp和_L之间的元素重新按反序排列,原来为逆序532,现在重排为235,于是得到容易{4235}  ,即是容器{3542}的下一个排列。
(7)、对于已经排成完全逆序的容器,如{5432},则先将其按反序重排为完全顺序{2345},然后返回false,因为其不存在下一个排列。

注意:在求容器的下一个排列时,总是要保证容器靠前的元素最小的不同排列,且如果得到完全逆序容器,则返回false,所以如果要求一个容器的全排列,应该先对该容器进行顺序排序,最后一点经过next_permutation()操作最后返回false后的容器为顺序的,应为该算法对完全逆序容器是先反序排列了之后再返回false的。

下面的程序在vc7.1下是有问题的,会发生死循环
include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>

using namespace std;

int main()
{
    // 经VC7编译执行后,会死循环,不可思议!
    // BCC5[o] G++[o] VC7[x]
    vector<int> p;
   
    p.push_back(2);
    p.push_back(2);
    p.push_back(1);

    do {
        copy(p.begin(), p.end(), ostream_iterator<int>(cout, " "));
        cout << "/n";
    } while (prev_permutation(p.begin(), p.end()));
}

依旧是VC7版发生死循环,看来这真的是vc7中prev_permutation()的一个bug。http://www.dinkumware.com/    因为:Our documentation points out, for both prev_permutation and next_permutation that no two elements may have equivalent ordering.


原创粉丝点击