全排列

全排列的递归实现虽然简单,但不容易理解。在绘制了一个树形结构图后,终于看清了里面的计算过程。但是虽然理清了过程,还是不明白为什么会这样设计。尤其是在递归调用的前后分别进行一次交换操作,感觉总是摸不着头绪。内心深处有个声音,往往让你绞尽脑汁不得其解的问题越是你的软肋。记得在高中学数学的时候,往往会因为一个数学难题而想破头想一个晚上,最终解出来之后总有种任通二脉打开的感觉,会感觉之前做过的类似的问题也会豁然开朗很多,虽然浪费了很长时间在这一个问题上,但收获却是无法估量的。

工作之后,很难静下心来思考一个问题很长时间,尤其是算法问题。这就是考验一个人的关键时刻。静下心来,认真思考,浮躁只会让自己的困惑越积越多,直到困惑足以打破你的自信心,你就永远都无法在这个地方抬起头来!

回头来思考这个问题,看到这个图之后清晰多了。我们看到,

(1)以a开头后面跟着(b,c,d)的排列

(2)以b开头后面跟着(a,c,d)的排列

(3)以c开头后面跟着(a,b,d)的排列

(4)以d开头后面跟着(a,b,c)的排列

当前元素与它后面的元素(包含它自己)依次进行交换

第一个swap是进行交换,而第二个swap是上一次swap的逆操作,为了防止上一次swap对之后产生影响。

template <class T>
inline void Swap(T& a, T& b)
{
    // 交换a和b
    T temp = a; a = b; b = temp;
}
 
template<class T>
void Perm(T list[], int k, int m)
{
    //生成list [k:m ]的所有排列方式
    int i;
    if (k == m)
    {
         //输出一个排列方式
         for (i = 0; i <= m; i++)
             cout << list [i];
         cout << endl;
    }
    else // list[k:m]有多个排列方式
    {
         // 递归地产生这些排列方式
         for (i=k; i <= m; i++)
         {
             Swap (list[k], list[i]);
             Perm (list, k+1, m);
             Swap (list[k], list[i]);
         }
    }
}

非递归算法的实现过程

//交换数组a中下标为i和j的两个元素的值
void swap(int* a,int i,int j)
{
    a[i]^=a[j];
    a[j]^=a[i];
    a[i]^=a[j];
}
 
//将数组a中的下标i到下标j之间的所有元素逆序倒置
void reverse(int a[],int i,int j)
{
    for(;i<j;++i,--j)
    {
         swap(a,i,j);
    }
}
 
void print(int a[],int length)
{
    for(int i=0;i<length;++i)
         cout<<a[i]<<" ";
    cout<<endl;
}
 
//求取全排列,打印结果
void combination(int a[],int length)
{
    if(length<2) return;
 
    bool end=false;
    while(true)
    {
         print(a,length);
        
         int i,j;
         //找到不符合趋势的元素的下标i
         for(i=length-2;i>=0;--i)
         {
             if(a[i]<a[i+1]) break;
             else if(i==0) return;
         }
 
         for(j=length-1;j>i;--j)
         {
             if(a[j]>a[i]) break;
         }
        
         swap(a,i,j);
         reverse(a,i+1,length-1);
    }
}
原文地址:https://www.cnblogs.com/sdlwlxf/p/4645917.html