问题描述:

给定一个整数n,按字典序打印出1-n的所有全排列

问题解答:

1.用C++里的next_permutation函数

函数定义如下:

template<class BidirectionalIterator>
bool next_permutation(
      BidirectionalIterator _First, 
      BidirectionalIterator _Last
);
template<class BidirectionalIterator, class BinaryPredicate>
bool next_permutation(
      BidirectionalIterator _First, 
      BidirectionalIterator _Last,
      BinaryPredicate _Comp
 );

函数实现的原理:

从序列的最后一个元素开始向前扫描,直到找到两个位置上相邻的元素*i,*j(i,j为下标,j = i+1)且*i<*j,再从尾端找一个元素*k,*i<*k,将*i与*k交换,并将*j及之后的元素全部倒置

证明:

设给定序列为a1a2...aiai+1ai+2...an,且ai,ai+1为逆序扫描第一个找到的正序,则有ai < ai+1 > ai+2 > ai+3 > ... > an,

①假设ai > ak (∀k∈{i+2,...n}),那么直接交换ai与ai+1,设所得序列为a1'a2'...ai'ai+1'ai+2' ... an',那么a1'=a1...ai-1'=ai,ai' = ai+1,ai+1'=ai,ai+2'=ai+2,...,an'=an

再将ai+1'及之后的元素逆置一下,就可以得到ai+1'及之后字符的集合组成的串的最小字典序排列

为什么这种是最小的呢?

首先,如果改变ai之前的字符任意使得字典序变得更大,那么显然要比上述方法得到的字符串a1'...an'字典序要大;

又ai+1及之后的串已经是完全逆序,所以只改变这部分得到的字符串字典序不会更大;

②假设存在k∈{i+2..n},使得ai<ak,证明类似

ps:注意边界条件:当字符串已经为完全逆序(达到字典序最大)时,没有next_permutation

函数代码:

template<class BidirectionalIterator>
bool next_permutation(
      BidirectionalIterator first, 
      BidirectionalIterator last
)
{
    if(first == last)
        return false; //空序列

    BidirectionalIterator i = first;
    ++i;
    if(i == last)
        return false;  //一个元素,没有下一个序列了
    
    i = last;
    --i;

    for(;;) {
        BidirectionalIterator ii = i;
        --i;
        if(*i < *ii) {
            BidirectionalIterator j = lase;
            while(!(*i < *--j));

            iter_swap(i, j);
            reverse(ii, last);
            return true;
        }
        
        if(i == first) {
            reverse(first, last);  //全逆向,即为最小字典序列,如cba变为abc
            return false;
        }
    }

}

使用:

#include<iostream>
#include<cstdio>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>

using namespace std;

int main()
{
    int Array[5] = {1,2,3,4,5};
    for(int i = 0; i < 5; ++i)
    {
        printf("%d\t",Array[i]);
    }
    printf("\n");
    while(next_permutation(Array,Array + 5))
    {
        for(int i = 0; i < 5; ++i)
        {
            printf("%d\t",Array[i]);
        }
        printf("\n");
    }
    return 0;
}    
posted on 2014-04-04 18:56  mizz  阅读(504)  评论(0编辑  收藏  举报